<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: KRISHNA KISHOR TIRUPATI</title>
    <description>The latest articles on DEV Community by KRISHNA KISHOR TIRUPATI (@ktirupati).</description>
    <link>https://dev.to/ktirupati</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3898223%2F924d18d8-e8a5-4915-bb5c-1367a3a911e8.jpeg</url>
      <title>DEV Community: KRISHNA KISHOR TIRUPATI</title>
      <link>https://dev.to/ktirupati</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ktirupati"/>
    <language>en</language>
    <item>
      <title>Architectural Evaluation: Why We Re-Engineered AI Safety From Text Guardrails to Infrastructure Control Planes</title>
      <dc:creator>KRISHNA KISHOR TIRUPATI</dc:creator>
      <pubDate>Mon, 14 Sep 2026 19:44:20 +0000</pubDate>
      <link>https://dev.to/ktirupati/architectural-evaluation-why-we-re-engineered-ai-safety-from-text-guardrails-to-infrastructure-4m4c</link>
      <guid>https://dev.to/ktirupati/architectural-evaluation-why-we-re-engineered-ai-safety-from-text-guardrails-to-infrastructure-4m4c</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The open-source AI safety ecosystem includes mature tools for structured-output validation, conversational guardrails, sensitive-data detection, and prompt or response filtering. Frameworks such as Guardrails AI, LLM Guard, and NVIDIA NeMo Guardrails address important parts of this problem.&lt;/p&gt;

&lt;p&gt;But autonomous AI systems introduce a broader security question.&lt;/p&gt;

&lt;p&gt;An agent does not merely generate text. It can select models, retrieve untrusted context, invoke Model Context Protocol (MCP) servers, query databases, modify files, create pull requests, deploy applications, or trigger external business processes.&lt;/p&gt;

&lt;p&gt;For these systems, checking whether text is safe is not enough. The platform must also decide:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this identity permitted to perform this action, through this connector, against this resource, using these arguments, within this tenant and region—and does the action require approval?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the role of an AI infrastructure control plane.&lt;/p&gt;

&lt;p&gt;This article explains why we built &lt;a href="https://github.com/ktirupati/policyaware" rel="noopener noreferrer"&gt;PolicyAware&lt;/a&gt; around policy enforcement, MCP tool governance, risk classification, model routing, evaluation, and audit evidence rather than positioning it as another text-validation wrapper.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffy245o0aib4h7iwm36fh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffy245o0aib4h7iwm36fh.png" alt="Text guardrails and AI infrastructure control planes address complementary layers" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Guardrails and Control Planes Solve Different Problems
&lt;/h2&gt;

&lt;p&gt;Describing every guardrail framework as a basic string filter would be inaccurate. Some support model-based validation, programmable constraints, conversational flows, and structured-output enforcement.&lt;/p&gt;

&lt;p&gt;The architectural distinction is primarily about &lt;strong&gt;where enforcement occurs and what it governs&lt;/strong&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Text and conversational guardrails&lt;/th&gt;
&lt;th&gt;PolicyAware control plane&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary responsibility&lt;/td&gt;
&lt;td&gt;Validate prompts, responses, conversation flows, or output structures&lt;/td&gt;
&lt;td&gt;Govern requests, identities, models, tools, side effects, evaluations, and evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical inputs&lt;/td&gt;
&lt;td&gt;Prompt and model output&lt;/td&gt;
&lt;td&gt;Prompt, role, tenant, region, risk, connector, action, arguments, and policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common decisions&lt;/td&gt;
&lt;td&gt;Pass, fail, retry, repair, or filter&lt;/td&gt;
&lt;td&gt;Deny, require approval, allow, conditional allow, or transform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool governance&lt;/td&gt;
&lt;td&gt;Usually application-specific&lt;/td&gt;
&lt;td&gt;Connector/action policy through &lt;code&gt;ToolPolicyEngine&lt;/code&gt; and MCP proxying&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protocol awareness&lt;/td&gt;
&lt;td&gt;Product- and integration-dependent&lt;/td&gt;
&lt;td&gt;Inspects MCP JSON-RPC &lt;code&gt;tools/call&lt;/code&gt; requests before forwarding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model routing&lt;/td&gt;
&lt;td&gt;Usually outside validation&lt;/td&gt;
&lt;td&gt;Policy-aware routing based on risk, region, provider, cost, and availability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit evidence&lt;/td&gt;
&lt;td&gt;Validation results and logs&lt;/td&gt;
&lt;td&gt;Decisions, reason codes, matched policies, evaluations, and trace IDs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Library or framework integration&lt;/td&gt;
&lt;td&gt;Embedded SDK, middleware, CLI, MCP proxy, or HTTP sidecar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime implementation&lt;/td&gt;
&lt;td&gt;Varies by framework&lt;/td&gt;
&lt;td&gt;Local deterministic Python rules in the base package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;Depends on validators and model calls&lt;/td&gt;
&lt;td&gt;Must be benchmarked for the deployed policy and integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The approaches are not necessarily competitors. A control plane can use specialized guardrail frameworks as optional components while retaining deterministic policy as the final authority.&lt;/p&gt;

&lt;p&gt;PolicyAware supports this layered model through optional integrations with Presidio, Transformers-based classifiers, NeMo Guardrails, and Guardrails AI.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Why Autonomous Agents Need Action-Level Governance
&lt;/h2&gt;

&lt;p&gt;Consider an agent connected to a filesystem MCP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;filesystem.read_file
filesystem.write_file
filesystem.delete_file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From a language-model perspective, these are tool calls. From a security perspective, they represent substantially different risks.&lt;/p&gt;

&lt;p&gt;A production system may require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;developers can read approved files,&lt;/li&gt;
&lt;li&gt;writes require human approval,&lt;/li&gt;
&lt;li&gt;deletion is denied,&lt;/li&gt;
&lt;li&gt;paths outside an approved directory are blocked,&lt;/li&gt;
&lt;li&gt;sensitive arguments are redacted before forwarding,&lt;/li&gt;
&lt;li&gt;and every decision is associated with an identity and trace ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A prompt filter cannot enforce these rules reliably by examining conversation text alone. Enforcement must occur at the tool boundary before the MCP server receives the request.&lt;/p&gt;

&lt;p&gt;PolicyAware represents these requirements as deny-by-default policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp_filesystem_policy&lt;/span&gt;
&lt;span class="na"&gt;schema_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.2"&lt;/span&gt;
&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;

&lt;span class="na"&gt;connectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;filesystem&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp&lt;/span&gt;
    &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;read_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;allow&lt;/span&gt;
        &lt;span class="na"&gt;risk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;low&lt;/span&gt;
        &lt;span class="na"&gt;side_effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;
        &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;user.role_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;developer&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;security_engineer&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

      &lt;span class="na"&gt;write_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;require_approval&lt;/span&gt;
        &lt;span class="na"&gt;risk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
        &lt;span class="na"&gt;side_effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
        &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;user.role_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;developer&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

      &lt;span class="na"&gt;delete_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;
        &lt;span class="na"&gt;risk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;critical&lt;/span&gt;
        &lt;span class="na"&gt;side_effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This policy does not ask the model whether deleting a file seems appropriate. It evaluates a deterministic rule using the connector, action, identity, and request context.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. PolicyAware's Runtime Architecture
&lt;/h2&gt;

&lt;p&gt;PolicyAware separates governance into explicit, replaceable components.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn9il10fqoqadt2acyrg0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn9il10fqoqadt2acyrg0.png" alt="PolicyAware runtime decision flow from context inspection through audit evidence" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A typical request follows this lifecycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The application supplies the request and structured context.&lt;/li&gt;
&lt;li&gt;Data-protection checks detect PII, PHI, secrets, and sensitive values.&lt;/li&gt;
&lt;li&gt;Risk classification assigns a low, medium, high, or critical tier.&lt;/li&gt;
&lt;li&gt;Policy determines whether to deny, require approval, allow, or transform.&lt;/li&gt;
&lt;li&gt;Denied and approval-gated requests stop before execution.&lt;/li&gt;
&lt;li&gt;Allowed requests proceed to a model router or tool-policy engine.&lt;/li&gt;
&lt;li&gt;Runtime evaluation checks results for leakage, citations, and policy consistency.&lt;/li&gt;
&lt;li&gt;Audit components record the decision and supporting evidence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One important semantic property is that &lt;strong&gt;transformation does not grant access&lt;/strong&gt;. A redaction rule may modify an otherwise allowed request, but it cannot convert a denied action into an allowed one.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. First-Class MCP JSON-RPC Governance
&lt;/h2&gt;

&lt;p&gt;PolicyAware includes an MCP policy proxy that evaluates raw JSON-RPC traffic before a tool call reaches the underlying MCP server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tools/call"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"filesystem.read_file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"README.md"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Find records for jane@example.com"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proxy can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;evaluate identity, role, tenant, and agent context,&lt;/li&gt;
&lt;li&gt;inspect tool arguments for sensitive information,&lt;/li&gt;
&lt;li&gt;deny unauthorized actions,&lt;/li&gt;
&lt;li&gt;require approval for high-impact operations,&lt;/li&gt;
&lt;li&gt;redact permitted arguments before forwarding,&lt;/li&gt;
&lt;li&gt;return structured JSON-RPC errors,&lt;/li&gt;
&lt;li&gt;and pass non-tool protocol messages through unchanged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Test a request from the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware mcp check policyaware.yaml mcp-request.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Place a live stdio proxy in front of an MCP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware mcp proxy policyaware.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--connector&lt;/span&gt; filesystem &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent&lt;/span&gt; coding_agent &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt; developer &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--server-command&lt;/span&gt; &lt;span class="s2"&gt;"python filesystem_mcp_server.py"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When an action is denied, it is not forwarded to the real server. The client receives a structured JSON-RPC error containing the decision, connector, action, and policy context.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Structured Recovery Instead of Opaque Failure
&lt;/h2&gt;

&lt;p&gt;Policy violations should not necessarily crash an entire agent session. However, claiming that a policy engine automatically reroutes every trajectory would overstate what an enforcement layer can guarantee.&lt;/p&gt;

&lt;p&gt;PolicyAware returns structured outcomes that an orchestrator can handle deliberately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;deny&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;require_approval&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allow&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;transformed request data,&lt;/li&gt;
&lt;li&gt;reason codes,&lt;/li&gt;
&lt;li&gt;matched policies,&lt;/li&gt;
&lt;li&gt;remediation information,&lt;/li&gt;
&lt;li&gt;and trace identifiers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a graph-based agent, the application can convert those decisions into state transitions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;policyaware&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PolicyAwareNodeGuard&lt;/span&gt;

&lt;span class="n"&gt;guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PolicyAwareNodeGuard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;policyaware.yaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tool_policy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool-governance.yaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;summarize_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Customer record summarized safely.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;guarded_node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;guard_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summarize_customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A denied state can move to a safe-response node. An approval-required state can pause and enter a human-review workflow. A redacted request can continue with transformed data.&lt;/p&gt;

&lt;p&gt;The orchestrator remains responsible for state transitions, suspension, approval persistence, and resumption. PolicyAware supplies the decision and evidence needed to implement that behavior consistently.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Performance Without Unverifiable Claims
&lt;/h2&gt;

&lt;p&gt;A control plane adds work before and after execution. The objective is not literal zero overhead; it is predictable, measurable overhead appropriate to the protected action.&lt;/p&gt;

&lt;p&gt;PolicyAware's base enforcement path is local, deterministic, rules-based, and implemented in Python. The current public package should not be described as using a native C or Rust execution core.&lt;/p&gt;

&lt;p&gt;Optional integrations can change runtime characteristics substantially:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Presidio and spaCy add stronger privacy detection.&lt;/li&gt;
&lt;li&gt;Transformers, Torch, and ONNX add model-based classification.&lt;/li&gt;
&lt;li&gt;NeMo Guardrails and Guardrails AI add external guardrail behavior.&lt;/li&gt;
&lt;li&gt;Remote providers introduce network latency.&lt;/li&gt;
&lt;li&gt;Larger composed policies require additional evaluation work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The repository includes reproducible benchmarks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python benchmarks/benchmark_policy_engine.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--requests&lt;/span&gt; 1000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--concurrency&lt;/span&gt; 1

python benchmarks/benchmark_policy_engine.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--requests&lt;/span&gt; 1000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--concurrency&lt;/span&gt; 20 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benchmark reports median, p95, and p99 latency, total runtime, and requests per second.&lt;/p&gt;

&lt;p&gt;A credible result should document the PolicyAware and Python versions, operating system, hardware, policy size, input distribution, concurrency, enabled integrations, and external calls.&lt;/p&gt;

&lt;p&gt;The defensible performance position is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PolicyAware provides a local deterministic enforcement path, separates heavyweight integrations into optional dependencies, and includes tools for measuring overhead in the target environment.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  7. Embedded SDK vs. Infrastructure Boundary
&lt;/h2&gt;

&lt;p&gt;PolicyAware supports multiple deployment models, but they do not provide identical security boundaries.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Primary use&lt;/th&gt;
&lt;th&gt;Security consideration&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Embedded SDK&lt;/td&gt;
&lt;td&gt;Python applications and local checks&lt;/td&gt;
&lt;td&gt;Code in the same process may bypass enforcement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Gateway.chat(...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Central model control, routing, evaluation, and audit&lt;/td&gt;
&lt;td&gt;Requests must consistently pass through the gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ToolPolicyEngine&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Application-owned tool authorization&lt;/td&gt;
&lt;td&gt;The application must check policy before execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP stdio proxy&lt;/td&gt;
&lt;td&gt;Enforcement before MCP forwarding&lt;/td&gt;
&lt;td&gt;Tool permissions still require least privilege&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Framework callbacks&lt;/td&gt;
&lt;td&gt;Observation and evaluation&lt;/td&gt;
&lt;td&gt;Callbacks report; they are not a hard boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP sidecar&lt;/td&gt;
&lt;td&gt;Polyglot services and process separation&lt;/td&gt;
&lt;td&gt;Requires authentication and network controls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository scanner&lt;/td&gt;
&lt;td&gt;Pre-deployment governance analysis&lt;/td&gt;
&lt;td&gt;Static findings do not prove exploitability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For stronger separation, PolicyAware can run as an internal sidecar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;POLICYAWARE_SIDECAR_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;replace-with-secret-token

policyaware up &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--policy&lt;/span&gt; policyaware.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tool-policy&lt;/span&gt; tool-governance.yaml &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--require-auth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sidecar can have a separate process, service identity, deployment lifecycle, private network access, and audit stream.&lt;/p&gt;

&lt;p&gt;It should still be combined with IAM, TLS or mTLS, secret management, container isolation, scoped tool credentials, dependency scanning, and centralized monitoring.&lt;/p&gt;

&lt;p&gt;Policy authorization decides whether an operation may proceed. It does not replace operating-system sandboxing.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Selecting the Right Tool
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Choose a structured-output or conversational guardrail when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;schema-conformant output is the primary requirement,&lt;/li&gt;
&lt;li&gt;invalid responses should be retried or repaired,&lt;/li&gt;
&lt;li&gt;conversational flow constraints are needed,&lt;/li&gt;
&lt;li&gt;toxicity or vocabulary filtering is central,&lt;/li&gt;
&lt;li&gt;or the application has no high-impact tool execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Choose a conventional AI gateway when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;provider abstraction is the primary need,&lt;/li&gt;
&lt;li&gt;API-key management is central,&lt;/li&gt;
&lt;li&gt;retries and provider fallback are required,&lt;/li&gt;
&lt;li&gt;routing is based mainly on price, availability, or latency,&lt;/li&gt;
&lt;li&gt;or standard rate limiting is sufficient.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Choose PolicyAware when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;identities, tenants, regions, and risk must influence decisions,&lt;/li&gt;
&lt;li&gt;agents invoke MCP servers or external tools,&lt;/li&gt;
&lt;li&gt;read, write, delete, deploy, or payment actions need different controls,&lt;/li&gt;
&lt;li&gt;sensitive arguments must be redacted before forwarding,&lt;/li&gt;
&lt;li&gt;high-risk actions require approval,&lt;/li&gt;
&lt;li&gt;model routing must occur after policy evaluation,&lt;/li&gt;
&lt;li&gt;or audit evidence must connect requests, decisions, tools, models, and results.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use them together when:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;deterministic policy should remain the auditable authority,&lt;/li&gt;
&lt;li&gt;semantic or conversational signals should contribute evidence,&lt;/li&gt;
&lt;li&gt;an AI gateway should handle provider transport,&lt;/li&gt;
&lt;li&gt;and PolicyAware should govern whether an action is permitted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This layered architecture is stronger than expecting one library to solve every aspect of AI safety.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Shift Governance Left
&lt;/h2&gt;

&lt;p&gt;Runtime enforcement catches decisions as they happen. Repository scanning catches governance gaps before deployment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; html,json,sarif,markdown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scanner can identify likely issues such as exposed PII or secrets, direct model calls without governance, unmapped MCP tools, weak tool policies, routing and audit gaps, and invalid policy YAML.&lt;/p&gt;

&lt;p&gt;Policy contract checks detect drift between declared actions and application code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware contract check ./src &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--policy&lt;/span&gt; tool-governance.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For pull requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ktirupati/policyaware-action@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These findings support secure review and CI enforcement. Static analysis does not prove exploitability and does not replace runtime testing.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Current Boundaries and Limitations
&lt;/h2&gt;

&lt;p&gt;PolicyAware is an AI governance framework, not a universal security platform.&lt;/p&gt;

&lt;p&gt;It does not replace authentication and IAM, API gateways and WAFs, secret managers, application security testing, container isolation, endpoint security, secure memory, or secure development practices.&lt;/p&gt;

&lt;p&gt;Additional boundaries include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The embedded SDK is not a hard boundary against code already running in the same process.&lt;/li&gt;
&lt;li&gt;An allowed tool is not automatically sandboxed.&lt;/li&gt;
&lt;li&gt;Callback integrations observe and report but do not provide central execution control.&lt;/li&gt;
&lt;li&gt;Built-in semantic detection is intentionally lighter than dedicated ML classifiers.&lt;/li&gt;
&lt;li&gt;Approval decisions require an external durable workflow for suspension, identity verification, expiration, and resumption.&lt;/li&gt;
&lt;li&gt;Compliance evidence does not constitute legal certification.&lt;/li&gt;
&lt;li&gt;Performance depends on deployed policies, traffic, integrations, and infrastructure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Being explicit about these boundaries makes the architecture more credible. PolicyAware governs AI decisions and evidence; the surrounding platform owns identity, credentials, isolation, networking, and execution security.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. Production Evaluation Checklist
&lt;/h2&gt;

&lt;p&gt;Before introducing an AI control plane into production:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Model real roles, tenants, regions, and business actions.&lt;/li&gt;
&lt;li&gt;Keep MCP and tool policies deny-by-default.&lt;/li&gt;
&lt;li&gt;Separate read-only identities from destructive identities.&lt;/li&gt;
&lt;li&gt;Require approval for deploy, delete, payment, permission, and export actions.&lt;/li&gt;
&lt;li&gt;Store approval state durably and authenticate the approver.&lt;/li&gt;
&lt;li&gt;Use short-lived credentials and keep secrets out of agent state.&lt;/li&gt;
&lt;li&gt;Sandbox untrusted execution.&lt;/li&gt;
&lt;li&gt;Run golden datasets for allow, deny, redact, and approval decisions.&lt;/li&gt;
&lt;li&gt;Benchmark the exact production policy stack.&lt;/li&gt;
&lt;li&gt;Export decisions and execution outcomes to the same audit system.&lt;/li&gt;
&lt;li&gt;Test policy and code contracts in CI.&lt;/li&gt;
&lt;li&gt;Combine deterministic policy with optional semantic detection where required.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AI safety is no longer solely a prompt-and-response validation problem.&lt;/p&gt;

&lt;p&gt;Once an autonomous system can invoke tools and change external state, governance must operate across identity, context, risk, models, connectors, actions, arguments, approvals, and audit evidence.&lt;/p&gt;

&lt;p&gt;Text and conversational guardrails remain valuable. PolicyAware addresses a different architectural layer: the decision point between an AI system's intent and its real-world effects.&lt;/p&gt;

&lt;p&gt;The strongest design is not based on claims of zero overhead or mathematical security. It is based on explicit deny-by-default policy, enforcement before side effects, explainable decisions, measurable performance, honest security boundaries, least-privilege execution, and reviewable evidence.&lt;/p&gt;

&lt;p&gt;That is the infrastructure-control-plane model PolicyAware is building.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ktirupati/policyaware" rel="noopener noreferrer"&gt;PolicyAware on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ktirupati.github.io/policyaware/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pypi.org/project/policyaware/" rel="noopener noreferrer"&gt;PyPI package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ktirupati/policyaware/blob/main/docs/mcp-policy-proxy.md" rel="noopener noreferrer"&gt;MCP policy proxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ktirupati/policyaware/blob/main/docs/security-boundaries.md" rel="noopener noreferrer"&gt;Security boundaries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ktirupati/policyaware/blob/main/docs/benchmarks.md" rel="noopener noreferrer"&gt;Benchmarks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>architecture</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Overcoming the Performance Tax in AI Safety: Engineering a Low-Latency Control Plane for Autonomous Agents</title>
      <dc:creator>KRISHNA KISHOR TIRUPATI</dc:creator>
      <pubDate>Mon, 14 Sep 2026 19:08:58 +0000</pubDate>
      <link>https://dev.to/ktirupati/overcoming-the-performance-tax-in-ai-safety-engineering-a-low-latency-control-plane-for-autonomous-4i</link>
      <guid>https://dev.to/ktirupati/overcoming-the-performance-tax-in-ai-safety-engineering-a-low-latency-control-plane-for-autonomous-4i</guid>
      <description>&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;As enterprise AI systems move from single-turn retrieval-augmented generation (RAG) toward agents that plan, call tools, and modify external state, safety can no longer be treated only as text filtering.&lt;/p&gt;

&lt;p&gt;This article presents a practical control-plane approach using &lt;a href="https://github.com/ktirupati/policyaware" rel="noopener noreferrer"&gt;PolicyAware&lt;/a&gt;, an open-source Python framework for deny-by-default policy, PII and secret handling, MCP tool governance, model routing, runtime evaluation, repository scanning, and audit evidence.&lt;/p&gt;

&lt;p&gt;The goal is not to promise "zero overhead." The goal is to keep the common enforcement path local, deterministic, measurable, and separate from optional heavyweight ML integrations. Teams should benchmark median, p95, and p99 latency in their own request path before setting production objectives.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Why Text Guardrails Are Not Enough
&lt;/h2&gt;

&lt;p&gt;First-generation AI safety tools often treat security as an input/output problem: inspect the prompt, validate the response, and block suspicious text.&lt;/p&gt;

&lt;p&gt;That remains useful, but an autonomous workflow has a wider attack surface. An agent can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;choose a model or provider,&lt;/li&gt;
&lt;li&gt;retrieve untrusted context,&lt;/li&gt;
&lt;li&gt;call an MCP server,&lt;/li&gt;
&lt;li&gt;read or write files,&lt;/li&gt;
&lt;li&gt;execute database operations,&lt;/li&gt;
&lt;li&gt;create pull requests,&lt;/li&gt;
&lt;li&gt;deploy software,&lt;/li&gt;
&lt;li&gt;or trigger an external business process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important question is therefore not only &lt;strong&gt;"Is this text safe?"&lt;/strong&gt; It is also:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this actor allowed to perform this action, against this resource, in this tenant and region, with these arguments, at this risk level, and does it require human approval?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A control plane answers that question before the side effect occurs.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Text Validation vs. an AI Control Plane
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Text-focused guardrail&lt;/th&gt;
&lt;th&gt;PolicyAware control-plane approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary role&lt;/td&gt;
&lt;td&gt;Prompt/output inspection&lt;/td&gt;
&lt;td&gt;Request, model, tool, evaluation, and audit governance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decision context&lt;/td&gt;
&lt;td&gt;Mostly text&lt;/td&gt;
&lt;td&gt;Role, tenant, region, risk, connector, action, arguments, and policy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP awareness&lt;/td&gt;
&lt;td&gt;Usually application-specific&lt;/td&gt;
&lt;td&gt;JSON-RPC &lt;code&gt;tools/call&lt;/code&gt; inspection and connector/action mapping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decisions&lt;/td&gt;
&lt;td&gt;Commonly allow or block&lt;/td&gt;
&lt;td&gt;Deny, require approval, allow, conditional allow, and transform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data handling&lt;/td&gt;
&lt;td&gt;Detection or rejection&lt;/td&gt;
&lt;td&gt;Detect and optionally redact PII, PHI, secrets, and sensitive fields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Inline validator&lt;/td&gt;
&lt;td&gt;Embedded SDK, middleware, CLI, MCP proxy, or sidecar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime foundation&lt;/td&gt;
&lt;td&gt;Product-dependent&lt;/td&gt;
&lt;td&gt;Local, deterministic Python rules in the base package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heavy detection&lt;/td&gt;
&lt;td&gt;Often bundled&lt;/td&gt;
&lt;td&gt;Optional Presidio, Transformers, NeMo Guardrails, and Guardrails AI extras&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance claim&lt;/td&gt;
&lt;td&gt;Frequently generalized&lt;/td&gt;
&lt;td&gt;Benchmark locally; do not assume a universal latency number&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At the time of writing, the repository declares PolicyAware version &lt;strong&gt;0.4.4&lt;/strong&gt; and Python &lt;strong&gt;3.10+&lt;/strong&gt;. The base package is intentionally lightweight, with Pydantic, PyYAML, Typer, and Rich as core dependencies.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The Runtime Architecture
&lt;/h2&gt;

&lt;p&gt;PolicyAware separates governance into explicit engines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI App / RAG Pipeline / Agent
              |
              v
PolicyAware SDK / CLI / Middleware / Callback
              |
              v
Data Protection -&amp;gt; Risk Classification -&amp;gt; Policy Decision
                                           |       |
                                      deny/approval |
                                                   v
                                      Model Routing or Tool Governance
                                                   |
                                                   v
                                      Runtime Evaluation
                                                   |
                                                   v
                                      Audit Trace / Evidence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request lifecycle is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Construct a request with identity, tenant, application, region, task, and risk context.&lt;/li&gt;
&lt;li&gt;Inspect prompts and arguments for PII, PHI, secrets, and sensitive categories.&lt;/li&gt;
&lt;li&gt;Assign a deterministic risk tier: low, medium, high, or critical.&lt;/li&gt;
&lt;li&gt;Evaluate deny, approval, allow, and transform rules.&lt;/li&gt;
&lt;li&gt;Stop denied or approval-gated work before model or tool execution.&lt;/li&gt;
&lt;li&gt;Route allowed model requests or authorize a connector/action pair.&lt;/li&gt;
&lt;li&gt;Evaluate outputs for leakage, citations, and policy consistency.&lt;/li&gt;
&lt;li&gt;Emit traceable reason codes, matched policy IDs, decisions, and audit evidence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A key semantic rule is that &lt;strong&gt;transform rules do not grant access&lt;/strong&gt;. A redaction transform modifies an otherwise permitted request; it does not turn a denied request into an allowed one.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Quick Start: Govern a Raw Model Call
&lt;/h2&gt;

&lt;p&gt;Install the base package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;policyaware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a gateway and inspect a prompt before sending it to a provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;policyaware&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;gateway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;policyaware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_policy_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;policyaware.yaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;safe_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect_and_mutate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email jane@example.com about claim ACME-42.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;billing_admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;session_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;99x-delta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;risk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claims-assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;decision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;safe_prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;inspect_and_mutate(...)&lt;/code&gt; fails closed with &lt;code&gt;PermissionError&lt;/code&gt; for denied or approval-required requests. If policy permits redaction, it returns the transformed prompt and audit metadata through the same runtime path.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Governing MCP Tool Calls Before Execution
&lt;/h2&gt;

&lt;p&gt;MCP servers can expose powerful operations. A filesystem server, GitHub connector, database connector, or deployment tool should not receive a request until policy has evaluated the intended action.&lt;/p&gt;

&lt;p&gt;A deny-by-default MCP policy can distinguish read, write, and delete operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp_proxy_policy&lt;/span&gt;
&lt;span class="na"&gt;schema_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.2"&lt;/span&gt;
&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;

&lt;span class="na"&gt;connectors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;filesystem&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp&lt;/span&gt;
    &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;read_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;allow&lt;/span&gt;
        &lt;span class="na"&gt;risk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;low&lt;/span&gt;
        &lt;span class="na"&gt;side_effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;
        &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;user.role_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;developer&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;security_engineer&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

      &lt;span class="na"&gt;write_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;require_approval&lt;/span&gt;
        &lt;span class="na"&gt;risk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
        &lt;span class="na"&gt;side_effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
        &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;user.role_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;developer&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

      &lt;span class="na"&gt;delete_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;
        &lt;span class="na"&gt;risk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;critical&lt;/span&gt;
        &lt;span class="na"&gt;side_effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PolicyAware can inspect a raw JSON-RPC request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tools/call"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"filesystem.read_file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"README.md"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email jane@example.com"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the CLI for a deterministic policy check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware mcp check policyaware.yaml mcp-request.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or place a live stdio proxy in front of an MCP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware mcp proxy   policyaware.yaml   &lt;span class="nt"&gt;--connector&lt;/span&gt; filesystem   &lt;span class="nt"&gt;--agent&lt;/span&gt; coding_agent   &lt;span class="nt"&gt;--role&lt;/span&gt; developer   &lt;span class="nt"&gt;--server-command&lt;/span&gt; &lt;span class="s2"&gt;"python filesystem_mcp_server.py"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a denied tool call, the proxy returns a structured JSON-RPC error to the client instead of forwarding the request to the real server. Non-tool protocol messages such as &lt;code&gt;initialize&lt;/code&gt; pass through normally.&lt;/p&gt;

&lt;p&gt;Repository guide: &lt;a href="https://github.com/ktirupati/policyaware/blob/main/docs/mcp-policy-proxy.md" rel="noopener noreferrer"&gt;MCP Policy Proxy&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. LangGraph-Style Node and Tool Governance
&lt;/h2&gt;

&lt;p&gt;PolicyAware includes a dependency-free &lt;code&gt;PolicyAwareNodeGuard&lt;/code&gt; for graph-style agent workflows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;policyaware&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PolicyAwareNodeGuard&lt;/span&gt;

&lt;span class="n"&gt;guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PolicyAwareNodeGuard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;policyaware.yaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tool_policy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool-governance.yaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;summarize_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Customer record summarized safely.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;guarded_node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;guard_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summarize_customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The guard can inspect graph state before a node runs, block denied states, return approval-required decisions for high-risk work, evaluate MCP-style tool calls, and attach governance metadata back to state.&lt;/p&gt;

&lt;p&gt;This is more useful than throwing an opaque exception because the orchestrator receives a structured decision that can be logged, displayed, or routed to a durable approval workflow.&lt;/p&gt;

&lt;p&gt;Runnable example: &lt;a href="https://github.com/ktirupati/policyaware/tree/main/examples/langgraph-agent-governance" rel="noopener noreferrer"&gt;LangGraph Agent Governance&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Performance Engineering Without Benchmark Theater
&lt;/h2&gt;

&lt;p&gt;Policy enforcement adds work. The engineering objective is to make that work predictable and proportionate to risk.&lt;/p&gt;

&lt;p&gt;PolicyAware's base path is local and rules-based. Policy loading can be cached so YAML is not parsed on every request. Optional ML and external guardrail engines are intentionally separated because Presidio, Transformers, Torch, ONNX, NeMo Guardrails, and Guardrails AI can add model-loading time, container size, and request latency.&lt;/p&gt;

&lt;p&gt;The repository includes reproducible local benchmarks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python benchmarks/benchmark_policy_engine.py   &lt;span class="nt"&gt;--requests&lt;/span&gt; 1000   &lt;span class="nt"&gt;--concurrency&lt;/span&gt; 1

python benchmarks/benchmark_policy_engine.py   &lt;span class="nt"&gt;--requests&lt;/span&gt; 1000   &lt;span class="nt"&gt;--concurrency&lt;/span&gt; 20   &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benchmark reports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;median latency in microseconds,&lt;/li&gt;
&lt;li&gt;p95 latency,&lt;/li&gt;
&lt;li&gt;p99 latency,&lt;/li&gt;
&lt;li&gt;total runtime,&lt;/li&gt;
&lt;li&gt;and requests per second.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repository scanning can also be measured:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python benchmarks/benchmark_scan.py &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--iterations&lt;/span&gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A responsible latency statement should include the PolicyAware version, Python version, hardware, operating system, policy size, input distribution, concurrency, enabled extras, and whether external services were called.&lt;/p&gt;

&lt;p&gt;Do not copy a single development-machine number into a universal production SLA.&lt;/p&gt;

&lt;p&gt;Benchmark guide: &lt;a href="https://github.com/ktirupati/policyaware/blob/main/docs/benchmarks.md" rel="noopener noreferrer"&gt;Lightweight Benchmarks&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Choose the Right Enforcement Boundary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Best use&lt;/th&gt;
&lt;th&gt;Important boundary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Embedded SDK&lt;/td&gt;
&lt;td&gt;Fast adoption in Python apps and prototypes&lt;/td&gt;
&lt;td&gt;Code executing in the same process may bypass local checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Gateway.chat(...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Central model request control, routing, evaluation, and audit&lt;/td&gt;
&lt;td&gt;The application must send controlled requests through the gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool policy / MCP proxy&lt;/td&gt;
&lt;td&gt;Connector and action enforcement before side effects&lt;/td&gt;
&lt;td&gt;Approved tools still need OS-level isolation and least privilege&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LangChain/LlamaIndex callbacks&lt;/td&gt;
&lt;td&gt;Observation, streamed-token accounting, and reporting&lt;/td&gt;
&lt;td&gt;Callbacks observe; they are not a hard execution boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP sidecar&lt;/td&gt;
&lt;td&gt;Polyglot services and stronger process separation&lt;/td&gt;
&lt;td&gt;Requires authentication, private networking, and operational ownership&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;policyaware scan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Local and CI detection of governance gaps&lt;/td&gt;
&lt;td&gt;Static analysis does not prove runtime exploitability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For stronger enterprise separation, run PolicyAware as an internal sidecar or gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;POLICYAWARE_SIDECAR_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;replace-with-secret-token
policyaware up   &lt;span class="nt"&gt;--policy&lt;/span&gt; policyaware.yaml   &lt;span class="nt"&gt;--tool-policy&lt;/span&gt; tool-governance.yaml   &lt;span class="nt"&gt;--require-auth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sidecar can have separate process memory, service identity, deployment lifecycle, audit stream, and network policy. It should still be combined with TLS or mTLS, IAM, secret management, and least-privilege tool credentials.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Shift Governance Left with Repository Scanning
&lt;/h2&gt;

&lt;p&gt;Runtime checks are only one layer. PolicyAware also includes an offline governance linter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; html,json,sarif,markdown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scanner can identify likely risks such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PII, PHI, and secret exposure,&lt;/li&gt;
&lt;li&gt;direct model calls without governance,&lt;/li&gt;
&lt;li&gt;unmapped MCP tools,&lt;/li&gt;
&lt;li&gt;weak or missing tool policies,&lt;/li&gt;
&lt;li&gt;routing and audit gaps,&lt;/li&gt;
&lt;li&gt;and invalid policy YAML.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For pull requests, the repository links an official GitHub Action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ktirupati/policyaware-action@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Static findings are signals, not proof of exploitability. They should feed secure code review, policy tests, and CI decisions rather than replace them.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Production Checklist
&lt;/h2&gt;

&lt;p&gt;Before adopting an AI control plane in production:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Model real roles, tenants, regions, resources, and business actions in policy.&lt;/li&gt;
&lt;li&gt;Keep tool governance deny-by-default.&lt;/li&gt;
&lt;li&gt;Separate read-only identities from write, delete, deploy, and payment identities.&lt;/li&gt;
&lt;li&gt;Require approval for high-impact side effects.&lt;/li&gt;
&lt;li&gt;Store approval state durably and verify the approver's identity before resuming.&lt;/li&gt;
&lt;li&gt;Use short-lived credentials and keep secrets out of prompts and agent state.&lt;/li&gt;
&lt;li&gt;Sandbox untrusted execution with containers, Wasm, gVisor, Firecracker, or Kubernetes isolation.&lt;/li&gt;
&lt;li&gt;Run golden datasets for allow, deny, redact, and approval outcomes.&lt;/li&gt;
&lt;li&gt;Benchmark the exact production policy stack and optional integrations.&lt;/li&gt;
&lt;li&gt;Export policy decisions and execution results to audit, metrics, SIEM, or GRC systems.&lt;/li&gt;
&lt;li&gt;Run policy contract checks so YAML actions do not drift from tool function signatures.&lt;/li&gt;
&lt;li&gt;Treat prompt-injection defense as layered: deterministic policy, restricted tools, optional semantic signals, and human review.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  11. What PolicyAware Is—and Is Not
&lt;/h2&gt;

&lt;p&gt;PolicyAware is designed for LLM applications, RAG pipelines, MCP workflows, autonomous agents, and AI governance scans.&lt;/p&gt;

&lt;p&gt;It is not a replacement for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IAM and authorization,&lt;/li&gt;
&lt;li&gt;WAF or API gateway controls,&lt;/li&gt;
&lt;li&gt;application security testing,&lt;/li&gt;
&lt;li&gt;secrets management,&lt;/li&gt;
&lt;li&gt;container or process isolation,&lt;/li&gt;
&lt;li&gt;endpoint security,&lt;/li&gt;
&lt;li&gt;or secure software development practices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The embedded Python SDK is not a secure-memory boundary. PolicyAware can decide whether a tool call should run, but it does not itself sandbox an approved command. Optional semantic classifiers can improve detection, but deterministic policy remains the auditable enforcement base.&lt;/p&gt;

&lt;p&gt;These limitations are a strength when stated clearly: the framework owns AI governance decisions and evidence, while the platform continues to own identity, isolation, credentials, networking, and execution security.&lt;/p&gt;

&lt;p&gt;Read the full &lt;a href="https://github.com/ktirupati/policyaware/blob/main/docs/security-boundaries.md" rel="noopener noreferrer"&gt;security boundaries&lt;/a&gt; and &lt;a href="https://github.com/ktirupati/policyaware/blob/main/docs/limitations.md" rel="noopener noreferrer"&gt;limitations&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. Conclusion
&lt;/h2&gt;

&lt;p&gt;Text filtering remains part of AI safety, but autonomous systems require action-level governance.&lt;/p&gt;

&lt;p&gt;A useful AI control plane should answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;who is acting,&lt;/li&gt;
&lt;li&gt;what model or tool is being requested,&lt;/li&gt;
&lt;li&gt;which data and resources are involved,&lt;/li&gt;
&lt;li&gt;whether the action is allowed,&lt;/li&gt;
&lt;li&gt;whether sensitive values must be transformed,&lt;/li&gt;
&lt;li&gt;whether a human must approve,&lt;/li&gt;
&lt;li&gt;and what evidence must be retained.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PolicyAware provides an open-source implementation of that pattern through a lightweight Python package, deny-by-default YAML policy, MCP JSON-RPC interception, model routing, evaluation hooks, repository scanning, and audit traces.&lt;/p&gt;

&lt;p&gt;The credible path to low latency is not an unmeasured "zero-overhead" claim. It is a local deterministic fast path, selective use of heavier detectors, cached policy state, reproducible benchmarks, and continuous measurement in the real deployment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/ktirupati/policyaware" rel="noopener noreferrer"&gt;ktirupati/policyaware&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Documentation: &lt;a href="https://ktirupati.github.io/policyaware/" rel="noopener noreferrer"&gt;PolicyAware docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/policyaware/" rel="noopener noreferrer"&gt;policyaware&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Examples: &lt;a href="https://github.com/ktirupati/policyaware/tree/main/examples" rel="noopener noreferrer"&gt;Runnable examples&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>performance</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Stopping Runaway AI Loops: Implementing Enterprise FinOps and Observability with PolicyAware</title>
      <dc:creator>KRISHNA KISHOR TIRUPATI</dc:creator>
      <pubDate>Fri, 31 Jul 2026 00:23:23 +0000</pubDate>
      <link>https://dev.to/ktirupati/stopping-runaway-ai-loops-implementing-enterprise-finops-and-observability-with-policyaware-4o1n</link>
      <guid>https://dev.to/ktirupati/stopping-runaway-ai-loops-implementing-enterprise-finops-and-observability-with-policyaware-4o1n</guid>
      <description>&lt;p&gt;Autonomous agents don't just fail loudly—they fail expensively. A single misconfigured retry loop between an agent and an LLM can generate thousands of redundant tool calls and API requests before anyone notices, turning a minor logic bug into a five-figure cloud bill. &lt;strong&gt;PolicyAware&lt;/strong&gt; is built to be the operational safety net that catches this class of failure before it reaches your finance team's dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Recursive Agent Crisis
&lt;/h2&gt;

&lt;p&gt;Every SRE and platform engineer who has run agentic workloads in production has a version of this story. An agent is wired to call an LLM, interpret the response, and take an action—often invoking another tool, which produces output that gets fed straight back into the same LLM. Under normal conditions this loop terminates in a few steps. Under a bad prompt, a malformed tool response, or a subtle logic error, it doesn't.&lt;/p&gt;

&lt;p&gt;The agent gets stuck reasoning in circles: it calls a tool, receives an ambiguous or malformed result, decides the task is incomplete, and calls the LLM again to "retry." Each retry consumes tokens, each tool call hits a downstream API, and there is no natural circuit breaker unless one has been explicitly engineered. Within minutes, a single stuck session can produce:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thousands of duplicate or contradictory API calls to internal and third-party services.&lt;/li&gt;
&lt;li&gt;Sustained LLM token consumption that dwarfs normal daily usage.&lt;/li&gt;
&lt;li&gt;Cascading load on downstream systems that were never designed for machine-speed request volume.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the time monitoring dashboards catch the anomaly—if they catch it at all—the damage is already done: a runaway bill, a rate-limited API partner, or a compromised production database from thousands of unchecked write attempts. Traditional APM tools tell you a service is under load; they don't tell you an autonomous agent is the one generating that load, or why.&lt;/p&gt;

&lt;p&gt;This is why the recursive agent crisis is fundamentally a governance problem, not just a monitoring problem. Rate limits and cost alerts fire after the money is spent. What's needed is a control layer that understands agent intent and enforces limits before the damage compounds—which is exactly the role &lt;strong&gt;PolicyAware&lt;/strong&gt; plays in an enterprise AI stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Pre-Deployment Auditing with PolicyAware
&lt;/h2&gt;

&lt;p&gt;The cheapest place to catch a runaway-loop risk is before it ships. &lt;strong&gt;PolicyAware&lt;/strong&gt; includes a local static scanning tool designed to run directly in CI/CD, auditing a codebase for the structural issues that lead to recursive disasters and compliance gaps.&lt;/p&gt;

&lt;p&gt;Running the scanner locally or in a pipeline step is a single command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware scan &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command walks the repository and flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unshielded MCP tool definitions that expose destructive or high-cost operations without a corresponding &lt;strong&gt;PolicyAware&lt;/strong&gt; policy attached.&lt;/li&gt;
&lt;li&gt;Unbudgeted API routes—endpoints an agent can call that have no token, rate, or spend ceiling defined anywhere in the codebase.&lt;/li&gt;
&lt;li&gt;Missing termination conditions in agent loop logic, such as retry blocks without a max-iteration guard.&lt;/li&gt;
&lt;li&gt;Compliance gaps relative to your organization's baseline policy set, so a tool added by one team doesn't silently bypass governance rules enforced elsewhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical CI integration adds &lt;strong&gt;PolicyAware&lt;/strong&gt; as a required check before merge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/policyaware-scan.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PolicyAware Audit&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install PolicyAware&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pip install policyaware&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run PolicyAware scan&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;policyaware scan . --fail-on-critical&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With --fail-on-critical, &lt;strong&gt;PolicyAware&lt;/strong&gt; blocks the pull request outright if it detects an unshielded tool definition or an unbudgeted route reachable by an autonomous agent. This turns agent governance into a build-time gate rather than a production incident, giving SREs and platform teams the same shift-left guarantees they already expect from security and dependency scanning.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Runtime Cost Controls
&lt;/h2&gt;

&lt;p&gt;Static scanning catches structural risk before deployment, but recursive loops are a runtime phenomenon—so &lt;strong&gt;PolicyAware&lt;/strong&gt; also operates as a live infrastructure gateway, sitting in front of your LLM and tool endpoints and evaluating every request against a global budget in real time.&lt;/p&gt;

&lt;p&gt;Instead of trusting each agent instance to self-limit, &lt;strong&gt;PolicyAware&lt;/strong&gt; enforces token and request budgets centrally, at the proxy layer, so a single misbehaving session cannot silently exceed organizational limits. A typical runtime configuration looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# policy.yaml (runtime cost section)&lt;/span&gt;
&lt;span class="na"&gt;budgets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;max_tokens_per_minute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50000&lt;/span&gt;
    &lt;span class="na"&gt;max_requests_per_minute&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;

  &lt;span class="na"&gt;per_session&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;max_tokens_per_session&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20000&lt;/span&gt;
    &lt;span class="na"&gt;max_tool_calls_per_session&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;
    &lt;span class="na"&gt;max_retries_per_task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;

  &lt;span class="na"&gt;circuit_breaker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;identical_call_repeated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
      &lt;span class="na"&gt;window_seconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terminate_session&lt;/span&gt;
    &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="s"&gt;Session terminated by PolicyAware: repeated identical&lt;/span&gt;
      &lt;span class="s"&gt;tool calls detected, indicating a recursive loop.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this configuration, &lt;strong&gt;PolicyAware&lt;/strong&gt; enforces three layers of protection simultaneously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A global ceiling on tokens and requests per minute across the entire fleet of agents, preventing any combination of sessions from overwhelming shared infrastructure.&lt;/li&gt;
&lt;li&gt;A per-session budget that caps how much a single agent instance can consume before it is forced to stop and escalate to a human.&lt;/li&gt;
&lt;li&gt;A circuit breaker that detects the specific signature of a recursive loop—the same tool call repeated in a tight window—and terminates the session immediately, before it reaches the per-session ceiling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because &lt;strong&gt;PolicyAware&lt;/strong&gt; sits at the gateway layer rather than inside application code, these budgets apply uniformly across every agent, framework, and team using the platform. A new service doesn't need to reimplement cost controls; it inherits them automatically the moment it routes through &lt;strong&gt;PolicyAware&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Enterprise Observability Traces
&lt;/h2&gt;

&lt;p&gt;Budgets and circuit breakers stop the bleeding, but SRE teams also need forensic visibility into what happened, when, and why. &lt;strong&gt;PolicyAware&lt;/strong&gt; addresses this with native OpenTelemetry hooks that emit structured JSON telemetry on every prompt execution and tool invocation it mediates, with no custom instrumentation required.&lt;/p&gt;

&lt;p&gt;Each trace emitted by &lt;strong&gt;PolicyAware&lt;/strong&gt; captures the fields DevOps and compliance teams actually need during an incident review:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-30T23:41:12Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trace_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pa-8f2c1e9a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"session_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"agent-run-4471"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db.execute_sql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"decision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"denied"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"policy_rule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"block_destructive_sql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tokens_consumed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;812&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cumulative_session_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;19875&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"budget_remaining_pct"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"latency_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because these traces follow the OpenTelemetry spec, they plug directly into the observability stack most platform teams already run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stream traces into Datadog for real-time cost dashboards and anomaly alerting tied to specific agents or teams.&lt;/li&gt;
&lt;li&gt;Export metrics to Prometheus for budget-remaining and denial-rate gauges that feed existing SRE alerting rules.&lt;/li&gt;
&lt;li&gt;Visualize session-level token burn and policy denials in Grafana, correlated against the same infrastructure metrics used for every other production service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This native telemetry turns &lt;strong&gt;PolicyAware&lt;/strong&gt; from a silent enforcement layer into an auditable system of record. When finance asks why a token budget was exceeded, or compliance asks which sessions attempted a destructive database operation, the answer is a query away rather than a forensic reconstruction from scattered application logs.&lt;/p&gt;

&lt;p&gt;For any enterprise running generative AI or RAG architectures in production, this combination—pre-deployment scanning, runtime budget enforcement, and structured observability—is not an optional add-on. It is the baseline operational requirement for keeping autonomous agents financially and operationally accountable, and &lt;strong&gt;PolicyAware&lt;/strong&gt; is purpose-built to be the utility that delivers all three from a single control plane.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>sre</category>
      <category>observability</category>
      <category>finops</category>
    </item>
    <item>
      <title>Securing Autonomous AI Agents: Why PolicyAware is the Essential Control Plane for MCP Tool Execution</title>
      <dc:creator>KRISHNA KISHOR TIRUPATI</dc:creator>
      <pubDate>Thu, 30 Jul 2026 23:59:13 +0000</pubDate>
      <link>https://dev.to/ktirupati/securing-autonomous-ai-agents-why-policyaware-is-the-essential-control-plane-for-mcp-tool-execution-59dh</link>
      <guid>https://dev.to/ktirupati/securing-autonomous-ai-agents-why-policyaware-is-the-essential-control-plane-for-mcp-tool-execution-59dh</guid>
      <description>&lt;p&gt;Autonomous AI agents are no longer confined to sandboxes—they now execute real actions against databases, shells, and file systems in production. In that world, &lt;strong&gt;PolicyAware&lt;/strong&gt; is the missing control plane for MCP-based tool execution, giving engineering and security teams a way to govern agentic behavior without slowing down innovation.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The Shift to Agentic AI
&lt;/h2&gt;

&lt;p&gt;For most of the last decade, AI integration meant a static text chatbot bolted onto an app: prompt in, text out, no persistent state, no external capabilities. That model was low-risk because it was also low-power.&lt;/p&gt;

&lt;p&gt;Anthropic's Model Context Protocol (MCP) changes this equation. MCP formalizes how LLMs invoke external tools—databases, HTTP APIs, shell commands, file systems, internal services—through structured, typed tool calls. An MCP-enabled agent doesn't just generate SQL as text; it issues an explicit execute_sql tool invocation with arguments that run directly against production systems.&lt;/p&gt;

&lt;p&gt;This shift introduces three structural changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agents become orchestration layers, deciding which tools to call, when, and with what parameters.&lt;/li&gt;
&lt;li&gt;Tool executions become programmable, repeatable, and logged as first-class events.&lt;/li&gt;
&lt;li&gt;The blast radius of a single compromised session now extends to everything those tools can reach.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this environment, &lt;strong&gt;PolicyAware&lt;/strong&gt; introduces an architectural separation most stacks currently lack: an independent Agent Control Plane sitting between MCP agents and the tools they invoke. Instead of trusting the LLM to behave, &lt;strong&gt;PolicyAware&lt;/strong&gt; inspects, approves, or blocks every tool call at the argument level before it touches infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Action-Level Vulnerability
&lt;/h2&gt;

&lt;p&gt;Most teams experimenting with MCP still think in terms of classic prompt security: jailbreak detectors, content filters, safe-completion policies. These operate on unstructured text and try to prevent the model from generating problematic output. Useful, but blind to the new failure mode agent tooling introduces.&lt;/p&gt;

&lt;p&gt;With MCP, the critical risk surface is not the text the LLM prints—it's the actions it takes. A compromised or misaligned agent can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Construct a valid DELETE FROM customers WHERE ... statement and pass it to a database tool.&lt;/li&gt;
&lt;li&gt;Invoke a run_shell tool with arguments like rm -rf /var/lib/data or a piped remote script execution.&lt;/li&gt;
&lt;li&gt;Write files into a repository via a write_file tool, introducing poisoned dependencies or leaked secrets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Traditional prompt firewalls rarely see these actions in a meaningful way. They operate at the prompt-plus-completion boundary, not at the tool-plus-arguments boundary where actual damage occurs. If an LLM accepts a hidden prompt injection, it can respond with entirely innocuous text while still issuing a dangerous tool call underneath.&lt;/p&gt;

&lt;p&gt;Consider a realistic chain of events: a user opens a long-running MCP session; a retrieved web page contains a hidden instruction telling the agent to run a destructive query whenever it's later asked to "optimize a report"; the agent internalizes this; a legitimate request later arrives; the agent silently emits a tool call carrying a destructive SQL statement. To most observability stacks, this looks like a normal, syntactically valid MCP invocation. The vulnerability lives in the semantics of the action, not in the conversation text—which is exactly the gap &lt;strong&gt;PolicyAware&lt;/strong&gt; exists to close by enforcing zero-trust, deny-by-default policy over tool arguments themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. PolicyAware as the Shield: Zero-Trust Agent Control Plane
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PolicyAware&lt;/strong&gt; is deliberately not another LLM safety filter layered on top of prompts. It is an Agent Control Plane deployed alongside your MCP tools so that every agent-mediated action passes through a hardened, auditable approval path.&lt;/p&gt;

&lt;p&gt;Architecturally, &lt;strong&gt;PolicyAware&lt;/strong&gt; runs as a standalone proxy sitting between your MCP tool server and the real services those tools reach. Rather than an agent calling tools directly, it calls through &lt;strong&gt;PolicyAware&lt;/strong&gt;, which parses tool arguments at the protocol level, evaluates them against policy-as-code rules, and then forwards, modifies, or blocks the call with a structured error.&lt;/p&gt;

&lt;p&gt;Getting started is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;policyaware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, spin up the standalone &lt;strong&gt;PolicyAware&lt;/strong&gt; proxy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware up &lt;span class="nt"&gt;--config&lt;/span&gt; policy.yaml &lt;span class="nt"&gt;--port&lt;/span&gt; 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This launches a &lt;strong&gt;PolicyAware&lt;/strong&gt; control plane process bound to localhost:8080, reading enforcement rules from policy.yaml. MCP tools like db.execute_sql or system.shell are then pointed at this proxy instead of directly at the underlying database or shell. From the agent's perspective nothing changes—it still issues ordinary tool calls—but every invocation now flows through &lt;strong&gt;PolicyAware&lt;/strong&gt; before touching anything sensitive.&lt;/p&gt;

&lt;p&gt;Several properties make &lt;strong&gt;PolicyAware&lt;/strong&gt; particularly suited to enterprise AI architectures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero-trust by design: &lt;strong&gt;PolicyAware&lt;/strong&gt; assumes all agent requests are untrusted and requires explicit allow-listing of safe operations.&lt;/li&gt;
&lt;li&gt;Protocol-aware parsing: it distinguishes SELECT from DELETE, ls from rm, read-only HTTP calls from mutating writes.&lt;/li&gt;
&lt;li&gt;Policy-as-code workflow: security and DevOps teams manage rules in version-controlled YAML, reviewed with the same rigor as infrastructure-as-code.&lt;/li&gt;
&lt;li&gt;Standalone proxy topology: &lt;strong&gt;PolicyAware&lt;/strong&gt; deploys into an existing microservice mesh without modifying the LLM itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By elevating &lt;strong&gt;PolicyAware&lt;/strong&gt; to the control plane for MCP tool execution, teams decouple what an agent wants to do from what the system will actually allow—the core principle of zero-trust architecture, and the only realistic path to securing autonomous agents as they gain broader authority in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Policy-as-Code Example: Deny-by-Default Topology
&lt;/h2&gt;

&lt;p&gt;The heart of &lt;strong&gt;PolicyAware&lt;/strong&gt; is its policy-as-code model: allowed and denied agent behaviors are described in YAML and enforced by the proxy at runtime, giving security teams a concrete, reviewable contract for agent actions instead of relying on opaque model settings.&lt;/p&gt;

&lt;p&gt;A typical pattern for MCP-based stacks is deny-by-default: all tools and operations are blocked unless explicitly allowed, read-only operations are gated but easy to permit, and mutating operations require narrowly scoped, reviewed policies.&lt;/p&gt;

&lt;p&gt;Here is a simplified policy.yaml showing how &lt;strong&gt;PolicyAware&lt;/strong&gt; enforces this topology for a db.execute_sql tool and a system.shell tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny-by-default&lt;/span&gt;

&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db.execute_sql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;allowed_verbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;select&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;show&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;explain&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;block_destructive_sql&lt;/span&gt;
        &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;query_contains_any&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delete&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;drop&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;truncate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;update&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
        &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;
        &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;Destructive SQL verbs are not allowed for autonomous agents.&lt;/span&gt;
          &lt;span class="s"&gt;Use a supervised maintenance workflow instead.&lt;/span&gt;

  &lt;span class="na"&gt;system.shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;allowed_commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ls"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cat"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pwd"&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;block_wildcard_rm&lt;/span&gt;
        &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;command_regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rm&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;s+-rf&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;s+(/|&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;.)"&lt;/span&gt;
        &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;
        &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;Recursive delete commands are blocked in agentic workflows.&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;block_remote_scripts&lt;/span&gt;
        &lt;span class="na"&gt;match&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;command_contains_any&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;curl&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wget&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
        &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;
        &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="s"&gt;Downloading and executing remote scripts is not permitted&lt;/span&gt;
          &lt;span class="s"&gt;for autonomous agents.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration expresses several guarantees enforced by &lt;strong&gt;PolicyAware&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The global mode: deny-by-default ensures any tool, verb, or command not explicitly allowed is automatically blocked.&lt;/li&gt;
&lt;li&gt;For db.execute_sql, &lt;strong&gt;PolicyAware&lt;/strong&gt; parses the SQL and only permits queries whose leading verb is SELECT, SHOW, or EXPLAIN.&lt;/li&gt;
&lt;li&gt;A dedicated block_destructive_sql rule denies any query containing destructive verbs like DELETE, DROP, TRUNCATE, or UPDATE regardless of surrounding context.&lt;/li&gt;
&lt;li&gt;For system.shell, &lt;strong&gt;PolicyAware&lt;/strong&gt; restricts the agent to a small set of introspection commands and denies recursive deletes or remote script execution outright.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because &lt;strong&gt;PolicyAware&lt;/strong&gt; operates as a proxy, these rules apply uniformly across every agent and session using MCP tools. Teams can evolve policy.yaml exactly as they evolve Terraform or Kubernetes manifests—through code review, CI checks, and staged rollouts. When a new tool is introduced, it can start locked down and only gain specific, audited capabilities over time.&lt;/p&gt;

&lt;p&gt;For senior engineers and AI architects, this is the right level of control: &lt;strong&gt;PolicyAware&lt;/strong&gt; doesn't try to out-argue the model at the prompt level—it simply refuses to execute unsafe actions. For DevOps and security teams, it's a familiar pattern: centralize authorization and enforcement in a control plane, define security posture as code, and instrument everything for observability and incident response. As MCP-based agents take on more operational responsibility, &lt;strong&gt;PolicyAware&lt;/strong&gt; is positioned as the essential, open-source control plane standing between agentic intent and irreversible action.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>mcp</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Scan Your AI App for PII, Secrets, Tool Risks, RAG Gaps, and LLM Governance Issues with PolicyAware</title>
      <dc:creator>KRISHNA KISHOR TIRUPATI</dc:creator>
      <pubDate>Thu, 23 Jul 2026 14:46:26 +0000</pubDate>
      <link>https://dev.to/ktirupati/scan-your-ai-app-for-pii-secrets-tool-risks-rag-gaps-and-llm-governance-issues-with-policyaware-5e3h</link>
      <guid>https://dev.to/ktirupati/scan-your-ai-app-for-pii-secrets-tool-risks-rag-gaps-and-llm-governance-issues-with-policyaware-5e3h</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: AI features ship fast, governance arrives late
&lt;/h2&gt;

&lt;p&gt;Most teams don't start their AI journey with a governance plan -- they start with a demo. They wire in an LLM SDK, add some RAG, experiment with tools and agents, and only later realize that sensitive data, unapproved calls, and missing audit trails are scattered across the codebase.&lt;/p&gt;

&lt;p&gt;By that point, AI features are in production or close to it, and it's hard to answer basic questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where do we send PII or PHI in prompts?&lt;/li&gt;
&lt;li&gt;Which files call providers like OpenAI or Anthropic directly without going through our gateway?&lt;/li&gt;
&lt;li&gt;Which tools and agents can take risky actions without approval or budget limits?&lt;/li&gt;
&lt;li&gt;Where does RAG return answers without citations or grounding checks?&lt;/li&gt;
&lt;li&gt;How much of our LLM usage is actually covered by our policies and audit requirements?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PolicyAware exists to make those questions answerable. It's an open-source, policy-aware AI gateway and governance framework for LLM, RAG, MCP/tool, and AI-agent applications, with a CLI and Python API you can run locally in your own environment.&lt;/p&gt;

&lt;p&gt;This article focuses on one capability: local code scanning with &lt;code&gt;policyaware scan&lt;/code&gt;, which helps detect AI governance gaps in your repository without calling models or external services.&lt;/p&gt;

&lt;h2&gt;
  
  
  What &lt;code&gt;policyaware scan&lt;/code&gt; actually does
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;policyaware scan&lt;/code&gt; is a fast, local governance and compliance scanner for AI application repositories. It scans source code, policy files, notebooks, infrastructure configuration, and data pipeline code for risks that matter in LLM, RAG, MCP/tool, and agent-based systems.&lt;/p&gt;

&lt;p&gt;Important design choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It does &lt;strong&gt;not&lt;/strong&gt; call external services.&lt;/li&gt;
&lt;li&gt;It does &lt;strong&gt;not&lt;/strong&gt; call models.&lt;/li&gt;
&lt;li&gt;It does &lt;strong&gt;not&lt;/strong&gt; execute your project code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can run it safely on a laptop, CI runner, or secure build agent without changing how your application behaves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Governance areas it checks
&lt;/h3&gt;

&lt;p&gt;The scanner looks for issues across multiple AI-specific governance categories, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PII&lt;/strong&gt;: prompts or config containing emails, phone numbers, SSNs, or credit-card-like values that should be redacted before reaching models, tools, logs, or evaluators.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PHI&lt;/strong&gt;: patient identifiers, medical record language, diagnosis or prescription text that may require regulated-domain policies and redaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets&lt;/strong&gt;: hardcoded API keys, tokens, bearer tokens, and secret assignments that should be moved into secret managers or environment variables and rotated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct LLM calls&lt;/strong&gt;: direct usage of SDKs and frameworks such as OpenAI, Anthropic, Bedrock, Vertex AI, LiteLLM, Ollama, LlamaIndex, DSPy, and Semantic Kernel that bypass the PolicyAware gateway routing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provider governance gaps&lt;/strong&gt;: model and provider usage that isn't routed by approved provider, role, risk level, region, cost, or availability policy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP/tool governance risks&lt;/strong&gt;: function calls, LangChain tools, MCP connectors, and other tools that can take impactful actions without connector or action policies and approval requirements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous agent risks&lt;/strong&gt;: patterns like &lt;code&gt;while True&lt;/code&gt;, &lt;code&gt;agent.run&lt;/code&gt;, or auto-execution loops that don't enforce human approval, max iterations, budgets, or audit logging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG grounding and citation gaps&lt;/strong&gt;: retrieval, vector store and embedding usage where responses are not tied to sources, metadata, or citation checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data residency concerns&lt;/strong&gt;: external endpoints, regions, API bases, and cloud locations that may move regulated data outside approved boundaries without tenant or region constraints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost governance gaps&lt;/strong&gt;: model or agent calls without clear token, timeout, rate, retry, or budget limits at request and workflow levels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YAML policy quality&lt;/strong&gt;: policy schema errors and missing &lt;code&gt;default: deny&lt;/code&gt; rules that weaken deny-by-default behavior.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration governance&lt;/strong&gt;: &lt;code&gt;.env&lt;/code&gt;, YAML, JSON, Terraform, Docker, CI/CD files that hold credentials or sensitive values instead of secret manager references.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit gaps&lt;/strong&gt;: model and tool calls that lack trace/audit language, making it harder to reconstruct decisions, routes, evaluation results, and response metadata later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From a platform or security perspective, this helps teams see AI-specific risks that traditional SAST or generic secret scanners often miss, especially around RAG behavior, tool orchestration, agent loops, and policy coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;PolicyAware is published on PyPI, so you can install it like any other Python tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;policyaware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're working directly from the PolicyAware repository, there's also a development install option documented in the wiki, but for most enterprise users &lt;code&gt;pip install policyaware&lt;/code&gt; is enough to get started with the CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start: scan a local folder and open the HTML report
&lt;/h2&gt;

&lt;p&gt;To run a basic local scan against an AI application folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware scan ./mylocalfolder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, this generates an HTML report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;policyaware-scan-report.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can tell the CLI to open the report automatically in your browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware scan ./mylocalfolder &lt;span class="nt"&gt;--open&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a good "first touch" workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the scan against a sample or production-like project.&lt;/li&gt;
&lt;li&gt;Open the HTML report.&lt;/li&gt;
&lt;li&gt;Review the executive summary and severity counts.&lt;/li&gt;
&lt;li&gt;Click into the findings by file and category to see what the scanner is actually flagging.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For AI platform, security, and compliance engineers, this is a low-friction way to surface governance issues without introducing latency into production traffic or forcing teams to adopt a full gateway orchestration on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiple report formats for humans, CI, and automation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;policyaware scan&lt;/code&gt; supports multiple output formats so you can serve developers, reviewers, and automated workflows with the same scan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt; html,json,sarif,markdown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's how those formats are typically used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML&lt;/strong&gt;: for humans -- developers, policy engineers, security reviewers, and compliance teams reviewing findings, remediation recommendations, and coverage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON&lt;/strong&gt;: for automation -- pipelines that push findings into internal dashboards, ticketing systems, or governance workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SARIF&lt;/strong&gt;: for GitHub code scanning and similar platforms that understand SARIF and can show findings inline in pull requests and repository views.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Markdown&lt;/strong&gt;: for review notes, compliance summaries, and documentation PRs where you want to include finding lists and remediation checklists in plain text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, teams often generate all four formats in CI and let different personas consume whichever format fits their workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI usage: fail builds on high-risk AI governance gaps
&lt;/h2&gt;

&lt;p&gt;You can use &lt;code&gt;policyaware scan&lt;/code&gt; in CI to enforce a minimum governance bar before merging AI changes. For example, failing the pipeline when the scan finds high-severity issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;policyaware scan &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--fail-on&lt;/span&gt; high
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A GitHub Actions workflow that wires this into pull requests and pushes to &lt;code&gt;main&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PolicyAware Scan&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v5&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.12"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install PolicyAware&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python -m pip install policyaware&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run scan&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;policyaware scan . --format html,json,sarif,markdown --fail-on high&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup supports governance review by catching high-risk PII, PHI, secrets, LLM routing gaps, unapproved tools, and agent risks before they land in &lt;code&gt;main&lt;/code&gt;, while still letting lower-severity findings through for future remediation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example findings PolicyAware Scan can flag
&lt;/h2&gt;

&lt;p&gt;To make this concrete, here are some example patterns the scanner can flag in an LLM/RAG/agent repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hardcoded API keys&lt;/strong&gt;: secrets like &lt;code&gt;OPENAI_API_KEY = "sk_live_..."&lt;/code&gt; or bearer tokens in Python, JS, YAML, or &lt;code&gt;.env&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts containing PII&lt;/strong&gt;: system or user prompts that include email addresses or phone numbers, especially in templates reused across multiple flows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct OpenAI or Anthropic SDK calls&lt;/strong&gt;: imports and calls to provider SDKs where requests bypass the PolicyAware gateway and its routing policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LangChain tools without an approval policy&lt;/strong&gt;: tool definitions that can make HTTP calls, read/write files, or trigger external systems without connector or action policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG response paths without citation checks&lt;/strong&gt;: retrieval and response code that surfaces answers to users without verifying sources or enforcing citation formatting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent loops without budgets or max iterations&lt;/strong&gt;: &lt;code&gt;while True&lt;/code&gt; loops or agent-run patterns that can incur unbounded cost or perform repeated, unreviewed actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing audit traces&lt;/strong&gt;: model or tool calls where no logging, tracing, or audit metadata is attached, making investigations and compliance reviews harder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YAML policies without &lt;code&gt;default: deny&lt;/code&gt;&lt;/strong&gt;: policy files that allow actions by default instead of requiring explicit allow rules, which can weaken your governance posture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each finding in the HTML report includes redacted evidence and suggested remediation, so developers can see what triggered the finding and how to address it without exposing sensitive values in the report itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the HTML report matters for developers and reviewers
&lt;/h2&gt;

&lt;p&gt;The HTML report is designed to be readable by both engineers and governance stakeholders. It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Executive summary and overall risk.&lt;/li&gt;
&lt;li&gt;Severity counts and finding categories.&lt;/li&gt;
&lt;li&gt;Compliance area counts and compliance-area filters.&lt;/li&gt;
&lt;li&gt;Top recommendations and remediation checklist.&lt;/li&gt;
&lt;li&gt;Findings grouped by file, with redacted evidence and suggested fix snippets.&lt;/li&gt;
&lt;li&gt;Guardrails orchestration findings and policy coverage score.&lt;/li&gt;
&lt;li&gt;Governance reviewer summary and links to documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it possible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI platform engineers to triage findings and prioritize fixes across services.&lt;/li&gt;
&lt;li&gt;Security engineers to focus on secrets, provider routing, and guardrails.&lt;/li&gt;
&lt;li&gt;Compliance engineers to map findings to frameworks like SOC 2 or internal AI governance standards.&lt;/li&gt;
&lt;li&gt;Enterprise architects to see where policies are enforced versus where they're missing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of handing someone a raw JSON or SARIF file, you can share a single HTML report that surfaces the most important issues and gives teams a structured remediation path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python API: use LocalCodeScanner directly
&lt;/h2&gt;

&lt;p&gt;If you prefer to control scanning from Python instead of the CLI, PolicyAware exposes a &lt;code&gt;LocalCodeScanner&lt;/code&gt; and &lt;code&gt;ScanConfig&lt;/code&gt; class you can use from your own scripts or orchestration tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;policyaware&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LocalCodeScanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ScanConfig&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ScanConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;examples/policyaware-scan.yaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalCodeScanner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;policyaware-scan-report.html&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;json_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;policyaware-scan-report.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;sarif_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;policyaware-scan-report.sarif&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;markdown_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;policyaware-scan-report.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;overall_risk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category_counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compliance_counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern lets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Embed scans into internal tooling or developer portals.&lt;/li&gt;
&lt;li&gt;Customize concurrency (&lt;code&gt;workers&lt;/code&gt;) and configuration.&lt;/li&gt;
&lt;li&gt;Generate multiple report formats in one call.&lt;/li&gt;
&lt;li&gt;Programmatically inspect &lt;code&gt;overall_risk&lt;/code&gt;, category counts, and compliance counts to drive additional automation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example scan config YAML
&lt;/h2&gt;

&lt;p&gt;You can customize what &lt;code&gt;policyaware scan&lt;/code&gt; looks at and which categories it enables by adding a YAML scan configuration file. A simple example looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;include_extensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.py&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.yaml&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.json&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.ipynb&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.tf&lt;/span&gt;

  &lt;span class="na"&gt;exclude_dirs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tests/fixtures&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;generated&lt;/span&gt;

  &lt;span class="na"&gt;enabled_categories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PII&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PHI&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Secrets&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LLM Governance&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MCP/Tool Governance&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RAG Governance&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Guardrails Integration&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Audit Gaps&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Configuration Governance&lt;/span&gt;

  &lt;span class="na"&gt;max_file_size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1mb&lt;/span&gt;
  &lt;span class="na"&gt;max_findings_per_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration focuses the scanner on Python, notebook, config, and Terraform files, skips fixtures and generated content, and enables governance categories that matter for many enterprise AI applications. You can tune this for your environment, including severity overrides, disabled categories, ignore patterns, and baselines as documented in the Local Code Scan wiki page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where PolicyAware Scan fits relative to SAST and security scanners
&lt;/h2&gt;

&lt;p&gt;PolicyAware Scan is not a replacement for SAST tools, generic secret scanners, or cloud security platforms, and it does not guarantee compliance or replace full security review. Instead, it focuses specifically on AI governance and LLM application risks.&lt;/p&gt;

&lt;p&gt;A practical way to think about it:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool type&lt;/th&gt;
&lt;th&gt;Primary focus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SAST&lt;/td&gt;
&lt;td&gt;General code vulnerabilities (injections, unsafe APIs, insecure patterns).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret scanners&lt;/td&gt;
&lt;td&gt;Credentials and tokens in code, config, and history.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud security tools&lt;/td&gt;
&lt;td&gt;Infrastructure misconfigurations, network exposure, IAM policies, runtime drift.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PolicyAware Scan&lt;/td&gt;
&lt;td&gt;AI governance gaps around LLMs, RAG, tools, agents, policies, audit, and compliance.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep using SAST for core application security.&lt;/li&gt;
&lt;li&gt;Keep using secret scanners and cloud security tools for infrastructure, dependencies, and credentials.&lt;/li&gt;
&lt;li&gt;Use PolicyAware Scan to add an AI governance lens across your AI-specific code, policies, and orchestration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This layered approach gives platform and security teams better coverage without overclaiming what any single tool can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links and further reading
&lt;/h2&gt;

&lt;p&gt;If you want to go deeper or integrate this into your own platform, the key links are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/policyaware/" rel="noopener noreferrer"&gt;https://pypi.org/project/policyaware/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/ktirupati/policyaware" rel="noopener noreferrer"&gt;https://github.com/ktirupati/policyaware&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://ktirupati.github.io/policyaware/" rel="noopener noreferrer"&gt;https://ktirupati.github.io/policyaware/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Local Code Scan Wiki: &lt;a href="https://github.com/ktirupati/policyaware/wiki/Local-Code-Scan" rel="noopener noreferrer"&gt;https://github.com/ktirupati/policyaware/wiki/Local-Code-Scan&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These include additional examples, ready-to-use YAML templates, CLI reference, and governance guidance for LLM, RAG, tools, agents, and audit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Local governance scanning won't solve every AI risk in one shot, but it does give your team visibility into where sensitive data, provider calls, tools, agents, and policies show up in the code -- and where your current governance posture has gaps.&lt;/p&gt;

&lt;p&gt;Try it on a local AI app, open the HTML report, and fix the highest-risk governance gaps first.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>PolicyAware vs Guardrails vs AI Gateways vs Model Routers: The Comparison Every AI Engineer Needs to Read</title>
      <dc:creator>KRISHNA KISHOR TIRUPATI</dc:creator>
      <pubDate>Sat, 23 May 2026 15:43:16 +0000</pubDate>
      <link>https://dev.to/ktirupati/policyaware-vs-guardrails-vs-ai-gateways-vs-model-routers-the-comparison-every-ai-engineer-needs-289p</link>
      <guid>https://dev.to/ktirupati/policyaware-vs-guardrails-vs-ai-gateways-vs-model-routers-the-comparison-every-ai-engineer-needs-289p</guid>
      <description>&lt;p&gt;I've been building AI-powered features for a while now, and the hardest conversations I have with my team are never about which model to use. They're always about the same thing: &lt;em&gt;what is this system actually allowed to do, and how do we prove it?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That question pushed me to build &lt;a href="https://github.com/ktirupati/policyaware" rel="noopener noreferrer"&gt;PolicyAware&lt;/a&gt; - an open source Python control plane that sits in front of your models, tools, and retrieval systems. Before I explain what it does, I want to walk through why the tools most teams reach for first - guardrails, AI gateways, and model routers - are genuinely useful but leave a critical gap wide open.&lt;/p&gt;




&lt;h2&gt;
  
  
  The landscape right now
&lt;/h2&gt;

&lt;p&gt;If you search for "AI safety" or "LLM governance" you will find three categories of tools coming up again and again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Guardrail libraries&lt;/strong&gt; - validate prompts and outputs against safety rules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI gateways&lt;/strong&gt; - proxy your requests to model providers, centralize API keys&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model routers&lt;/strong&gt; - pick the cheapest or fastest model for each request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three are useful. None of them alone answers the governance question.&lt;/p&gt;

&lt;p&gt;Here is the mental model I use: a guardrail checks &lt;em&gt;what&lt;/em&gt; the model says. A gateway manages &lt;em&gt;where&lt;/em&gt; the request goes. A router decides &lt;em&gt;which model&lt;/em&gt; handles it. But none of them ask the most important question first: &lt;strong&gt;should this request be allowed to run at all, under this user's role, for this tenant, in this region, given this risk level?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the gap PolicyAware fills.&lt;/p&gt;




&lt;h2&gt;
  
  
  Side-by-side comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Guardrails&lt;/th&gt;
&lt;th&gt;AI Gateway&lt;/th&gt;
&lt;th&gt;Model Router&lt;/th&gt;
&lt;th&gt;PolicyAware&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Block unsafe prompts before execution&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redact PII / PHI / secrets pre-execution&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decisions using role, tenant, region, risk&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deny-by-default posture&lt;/td&gt;
&lt;td&gt;Usually no&lt;/td&gt;
&lt;td&gt;Usually no&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Govern MCP / agent tool calls&lt;/td&gt;
&lt;td&gt;Usually no&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Require human approval for risky actions&lt;/td&gt;
&lt;td&gt;Usually no&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Route across providers after policy approval&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluate RAG citation, grounding, leakage&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Emit audit traces with reason codes&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generate compliance evidence artifacts&lt;/td&gt;
&lt;td&gt;Usually no&lt;/td&gt;
&lt;td&gt;Usually no&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The right column is not a flex. It is a description of what enterprise AI systems actually need once they move beyond read-only chat and start touching real data, real tools, and real business workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  When each tool is the right call
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use a guardrails library when&lt;/strong&gt; your only need is response formatting, toxicity filtering, or structured output validation. If you do not need RBAC, tenant rules, approval flows, or audit evidence, a guardrail is lighter and faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use an AI gateway when&lt;/strong&gt; your main problem is juggling provider keys, rate limits, and fallback routing. Gateways are great infrastructure. They are just not governance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use a model router when&lt;/strong&gt; you are optimizing for cost, latency, or quality tradeoffs across providers. A router does not decide whether a request &lt;em&gt;should&lt;/em&gt; run - only which model &lt;em&gt;would&lt;/em&gt; run it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use PolicyAware when&lt;/strong&gt; your AI system touches sensitive data, calls external tools, operates under regional compliance rules, or takes actions with financial or operational consequences. If you need to explain a decision to a security team six months from now, you need a control plane, not just a proxy.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the architecture fits together
&lt;/h2&gt;

&lt;p&gt;Here is the pattern I use in production. The key rule is: nothing reaches a model, retriever, or tool until the control plane has made an explicit decision.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-----------------------------+
| Application Layer           |
| (web app / API / workflow)  |
+-------------+---------------+
              |
              v
+-----------------------------+
| PolicyAware Control Plane   |
|                             |
|  1. Identity + context      |
|  2. Deny-by-default check   |
|  3. PII / PHI detection     |
|  4. Risk classification     |
|  5. Approval gate (if high) |
|  6. Provider routing        |
+--------+----------+---------+
         |          |
         v          v
  +----------+  +----------+
  | RAG Layer|  | Tools /  |
  | retrieval|  | MCP      |
  | citation |  | payments |
  +----+-----+  +----+-----+
       |              |
       +------+-------+
              |
              v
       +-------------+
       | Model Layer |
       | (local/SaaS)|
       +------+------+
              |
              v
       +-------------+
       | Evaluations |
       | leakage     |
       | grounding   |
       | audit trace |
       +-------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every arrow in that diagram has a policy decision attached to it. That is the entire point.&lt;/p&gt;




&lt;h2&gt;
  
  
  A real example: the $500 refund prompt
&lt;/h2&gt;

&lt;p&gt;Let us make this concrete. A customer-support copilot gets this message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Email jane@example.com and refund the customer $500.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is what different tools do with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;guardrail&lt;/strong&gt; might check whether the output looks safe&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;gateway&lt;/strong&gt; forwards the request to your provider of choice&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;router&lt;/strong&gt; picks GPT-4.1 because it is the best model for support tasks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PolicyAware&lt;/strong&gt; stops and works through the full decision tree before any of that happens&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Code: policy-first middleware
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Decision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ALLOW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;DENY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deny&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;REQUIRE_APPROVAL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;require_approval&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RequestContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;task_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PolicyResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decision&lt;/span&gt;
    &lt;span class="n"&gt;risk_tier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;redacted_prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;required_approver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

&lt;span class="n"&gt;EMAIL_RE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ALLOWED_TOOLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;knowledge_search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;draft_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;finance_manager&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;knowledge_search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;draft_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;issue_refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RequestContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;PolicyResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;reason_codes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;allowed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ALLOWED_TOOLS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;PolicyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DENY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;risk_tier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;redacted_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;EMAIL_RE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[REDACTED]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_not_permitted:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;redacted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EMAIL_RE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[REDACTED]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;EMAIL_RE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pii_detected&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;is_high_risk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;issue_refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_high_risk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high_risk_financial_action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;PolicyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REQUIRE_APPROVAL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;risk_tier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;redacted_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;redacted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;required_approver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;finance_supervisor&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;policy_allow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;PolicyResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ALLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;risk_tier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;redacted_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;redacted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Try the refund prompt
&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RequestContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;u-1001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;acme-corp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;task_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_support&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email jane@example.com and refund the customer $500.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;draft_email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;issue_refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;evaluate_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# Decision.DENY
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# ['tool_not_permitted:issue_refund']
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The support agent gets denied before the prompt ever reaches a model. The reason code is logged. The redacted prompt is stored. That is the audit trail your security team will ask for.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code: compliant model routing
&lt;/h2&gt;

&lt;p&gt;Routing still matters - but it should only happen after policy approves the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RouteDecision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="n"&gt;COMPLIANT_MODELS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;azure_openai&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;local_vllm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llama-3.1-70b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu-west&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;azure_openai_eu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;local_vllm_eu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;llama-3.1-70b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;route_after_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PolicyResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RequestContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;RouteDecision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;Decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ALLOW&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;PermissionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot route - decision is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;COMPLIANT_MODELS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No compliant providers for region: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;RouteDecision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;policy-approved compliant route&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A traditional router asks: &lt;em&gt;which model is fastest?&lt;/em&gt; This asks: &lt;em&gt;which model is allowed?&lt;/em&gt; The order of those questions changes everything about your compliance posture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code: audit trace
&lt;/h2&gt;

&lt;p&gt;This is the piece most teams skip - and regret during their first security review.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;emit_audit_trace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RequestContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PolicyResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;trace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tenant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;decision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;risk_tier&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;risk_tier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reason_codes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools_requested&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;route&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provider&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt_preview&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redacted_prompt&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample output for the denied refund request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-05-23T15:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"u-1001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tenant"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"acme-corp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"task_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"customer_support"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"decision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deny"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"risk_tier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reason_codes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"tool_not_permitted:issue_refund"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools_requested"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"draft_email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"issue_refund"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"route"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prompt_preview"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email [REDACTED] and refund the customer $500."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every denied request, every approval gate, every route choice - all replayable. That is the evidence layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Start using PolicyAware today
&lt;/h2&gt;

&lt;p&gt;PolicyAware is open source, MIT licensed, and published as a Python package. You do not need a SaaS contract. You do not need to rip out your existing stack. Drop it in as a middleware layer in front of your LLM calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;policyaware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simplest integration pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;policyaware&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;evaluate_policy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RequestContext&lt;/span&gt;

&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RequestContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;task_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_support&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;requested_tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;evaluate_policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_your_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redacted_prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;require_approval&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;request_human_approval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Request denied&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One function call between your application and your model. Policy first. Everything else second.&lt;/p&gt;




&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;Guardrails make your outputs safer. Gateways make your infrastructure cleaner. Routers make your model spend smarter. But none of them govern the full execution path.&lt;/p&gt;

&lt;p&gt;If your AI system is making decisions that touch real people, real money, or real compliance boundaries - you need a control plane that runs policy &lt;em&gt;before&lt;/em&gt; execution and produces evidence &lt;em&gt;after&lt;/em&gt; it.&lt;/p&gt;

&lt;p&gt;That is exactly what PolicyAware is built for. Star the repo, install the package, and let me know what governance problems you are running into - I am actively building this out in the open.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ktirupati/policyaware" rel="noopener noreferrer"&gt;https://github.com/ktirupati/policyaware&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;policyaware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>python</category>
      <category>ai</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Build a Policy-Aware AI Gateway in Python: Data Protection + Policy Enforcement with policyaware</title>
      <dc:creator>KRISHNA KISHOR TIRUPATI</dc:creator>
      <pubDate>Mon, 18 May 2026 04:33:30 +0000</pubDate>
      <link>https://dev.to/ktirupati/build-a-policy-aware-ai-gateway-in-python-data-protection-policy-enforcement-with-policyaware-462h</link>
      <guid>https://dev.to/ktirupati/build-a-policy-aware-ai-gateway-in-python-data-protection-policy-enforcement-with-policyaware-462h</guid>
      <description>&lt;p&gt;Most AI apps ship without any real governance layer. Prompts flow raw to models, sensitive data ends up in logs, and nobody finds out until a compliance audit or a breach. I built &lt;code&gt;policyaware&lt;/code&gt; to fix that — a Python-first package that gives you &lt;strong&gt;data protection&lt;/strong&gt; and &lt;strong&gt;policy enforcement&lt;/strong&gt; in front of any AI system.&lt;/p&gt;

&lt;p&gt;This article is a hands-on technical walkthrough. Every section has working code. By the end you will have a pattern you can wire into any AI gateway or agent pipeline today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;!&lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;policyaware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ktirupati/policyaware" rel="noopener noreferrer"&gt;https://github.com/ktirupati/policyaware&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Wiki:&lt;/strong&gt; &lt;a href="https://github.com/ktirupati/policyaware/wiki" rel="noopener noreferrer"&gt;https://github.com/ktirupati/policyaware/wiki&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Part 1 — Data Protection
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What the engine detects
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;DataProtectionEngine&lt;/code&gt; scans any string and returns a structured &lt;code&gt;DataFindings&lt;/code&gt; object. It classifies content into three buckets:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bucket&lt;/th&gt;
&lt;th&gt;What it catches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PII&lt;/td&gt;
&lt;td&gt;email, phone, SSN, credit card&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHI&lt;/td&gt;
&lt;td&gt;medical record, patient ID, diagnosis, medication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets&lt;/td&gt;
&lt;td&gt;API keys, bearer tokens, private keys&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Inspecting a prompt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;policyaware&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DataProtectionEngine&lt;/span&gt;

&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hi, I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m Jane. Reach me at jane@example.com or 212-555-7890.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataProtectionEngine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;findings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains_pii&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;# True
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains_phi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;# False
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains_secrets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# False
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contains_sensitive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# True  (aggregate flag)
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# ['email', 'phone']
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redactions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# 2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  DataFindings field reference
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;contains_pii&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;email, phone, SSN, credit card detected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;contains_phi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;medical record, diagnosis, medication detected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;contains_secrets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;API key, bearer token, private key detected&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;contains_sensitive&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;bool&lt;/td&gt;
&lt;td&gt;True if any of the above is True&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;categories&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;list&lt;/td&gt;
&lt;td&gt;e.g. &lt;code&gt;['email', 'phone', 'ssn']&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;redactions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;Total number of matches found&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;redacted_text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;str&lt;/td&gt;
&lt;td&gt;Sanitised text returned by &lt;code&gt;.redact()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Part 2 — Policy Enforcement
&lt;/h2&gt;

&lt;p&gt;Data protection tells you &lt;em&gt;what&lt;/em&gt; is in the request. Policy enforcement tells you &lt;em&gt;what to do about it&lt;/em&gt;. The &lt;code&gt;PolicyEngine&lt;/code&gt; loads a YAML file and evaluates every request against your rules, returning a structured &lt;code&gt;PolicyDecision&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The four decision outcomes
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decision&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;allow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Request passes through, apply any transforms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deny&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Request is blocked outright&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;conditional_allow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Passes but triggers follow-up checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;require_approval&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Routes to a human-in-the-loop flow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;The engine is &lt;strong&gt;deny-by-default&lt;/strong&gt;. If no rule explicitly grants access, the request is blocked. No silent pass-throughs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Writing your first policy YAML
&lt;/h3&gt;

&lt;p&gt;Rules reference &lt;code&gt;DataFindings&lt;/code&gt; fields directly via the &lt;code&gt;data&lt;/code&gt; root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# support_policy.yaml&lt;/span&gt;
&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;support_policy&lt;/span&gt;
&lt;span class="na"&gt;schema_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.2"&lt;/span&gt;
&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;

&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="c1"&gt;# Rule 1: Block anything containing secrets (API keys, tokens)&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny_secret_leakage&lt;/span&gt;
    &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;data.contains_secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="c1"&gt;# Rule 2: Redact PII for standard users, but not for compliance officers&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redact_pii_standard_users&lt;/span&gt;
    &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;transform&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redact&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;data.contains_pii&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;user.role_not_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;privacy_admin&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;compliance_officer&lt;/span&gt;

  &lt;span class="c1"&gt;# Rule 3: Allow support agents in US for low/medium risk requests&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;allow_support_agents&lt;/span&gt;
    &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;allow&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;user.role_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;support_agent&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;support_manager&lt;/span&gt;
      &lt;span class="na"&gt;request.region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us&lt;/span&gt;
      &lt;span class="na"&gt;risk.tier_in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;low&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;medium&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enforcing the policy at runtime
&lt;/h3&gt;

&lt;p&gt;Load the YAML, build a &lt;code&gt;GatewayRequest&lt;/code&gt;, inspect the prompt, then call &lt;code&gt;decide&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;policyaware&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DataProtectionEngine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GatewayRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PolicyEngine&lt;/span&gt;

&lt;span class="c1"&gt;# Load policy from YAML file
&lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PolicyEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support_policy.yaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Build the request context
&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GatewayRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;tenant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;acme-corp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support-copilot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;u_001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;region&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;risk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email jane@example.com, urgent!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Step 1: inspect the prompt
&lt;/span&gt;&lt;span class="n"&gt;findings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataProtectionEngine&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prompt_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Step 2: evaluate policy
&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;findings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Step 3: act on the decision
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 'allow' / 'deny' / 'conditional_allow' / 'require_approval'
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# ['redact']
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;matched_rules&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# ['redact_pii_standard_users', 'allow_support_agents']
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;violated_rules&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# []
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="c1"&gt;# Human-readable explanation
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# Machine-readable codes for logging
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;risk_score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;# Numeric risk score
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;risk_tier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;# 'low' / 'medium' / 'high' / 'critical'
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remediation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# Suggested fix if blocked
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  PolicyDecision field reference
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;decision&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;enum&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;allow&lt;/code&gt;, &lt;code&gt;deny&lt;/code&gt;, &lt;code&gt;conditional_allow&lt;/code&gt;, &lt;code&gt;require_approval&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;actions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;list&lt;/td&gt;
&lt;td&gt;Transforms to apply e.g. &lt;code&gt;['redact']&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;matched_rules&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;list&lt;/td&gt;
&lt;td&gt;Rules that matched the request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;violated_rules&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;list&lt;/td&gt;
&lt;td&gt;Rules that were violated (for audit logs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reason&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;str&lt;/td&gt;
&lt;td&gt;Human-readable explanation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reason_codes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;list&lt;/td&gt;
&lt;td&gt;Machine-readable codes for dashboards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;risk_score&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;float&lt;/td&gt;
&lt;td&gt;Numeric risk score&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;risk_tier&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;str&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;low&lt;/code&gt;, &lt;code&gt;medium&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;, &lt;code&gt;critical&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;remediation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;str&lt;/td&gt;
&lt;td&gt;Suggested fix when request is blocked&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Policy Context Roots
&lt;/h2&gt;

&lt;p&gt;Inside every &lt;code&gt;when&lt;/code&gt; clause you can reference these roots:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Root&lt;/th&gt;
&lt;th&gt;Example usage&lt;/th&gt;
&lt;th&gt;What it covers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tenant&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tenant: acme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Customer or team identifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app: support-copilot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Calling application or service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;user&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;user.role_in: [support_agent]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Role, ID, department attributes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;request&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;request.region: us&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Region, task type, autonomy level&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;data.contains_pii: true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Output from &lt;code&gt;DataProtectionEngine&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;risk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;risk.tier_in: [low, medium]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Risk score and tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ml.prompt_injection.detected: true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Optional ML classifier signals&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Validate Policies Before Production
&lt;/h2&gt;

&lt;p&gt;Ship broken policies and you get silent misses or unintended blocks. &lt;code&gt;policyaware&lt;/code&gt; ships a schema validator and CLI to catch issues early.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Python validator:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;policyaware&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PolicySchemaValidator&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support_policy.yaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safe_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nc"&gt;PolicySchemaValidator&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# raises on schema errors
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CLI commands:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Validate the YAML schema&lt;/span&gt;
policyaware policy validate support_policy.yaml

&lt;span class="c"&gt;# Explain how a specific request flows through your rules&lt;/span&gt;
policyaware policy explain &lt;span class="nt"&gt;--request&lt;/span&gt; sample_request.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;explain&lt;/code&gt; command is especially useful in CI/CD pipelines — you can run policy checks against a suite of sample requests before merging.&lt;/p&gt;




&lt;h2&gt;
  
  
  Optional: ML-Assisted PII Detection with Presidio
&lt;/h2&gt;

&lt;p&gt;Regex-based rules miss things like names and addresses. For those, &lt;code&gt;policyaware&lt;/code&gt; supports an optional &lt;a href="https://microsoft.github.io/presidio/" rel="noopener noreferrer"&gt;Microsoft Presidio&lt;/a&gt; integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"policyaware[presidio]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;policyaware&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PresidioPIIClassifier&lt;/span&gt;

&lt;span class="n"&gt;classifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;PresidioPIIClassifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score_threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;assessment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;classify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Jane Doe lives at 120 Main St and her phone is 212-555-7890.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;assessment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="c1"&gt;# Returns detected entities with type, value, and confidence score
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Presidio findings feed back into the same &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;ml&lt;/code&gt; roots in your YAML, giving you deterministic + ML detection in one framework.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR — What You Get in One Package
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;How&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Detect PII, PHI, Secrets&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DataProtectionEngine().inspect(text)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redact sensitive content&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DataProtectionEngine().redact(text)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enforce access policies via YAML&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PolicyEngine.from_file("policy.yaml")&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rich audit-ready decisions&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PolicyDecision&lt;/code&gt; with reason, risk, remediation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ML-assisted detection&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PresidioPIIClassifier&lt;/code&gt; (optional extra)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validate policies before shipping&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;PolicySchemaValidator&lt;/code&gt; + CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Get Started Now
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;!&lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;policyaware
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the fastest path to seeing value:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the package&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;DataProtectionEngine().inspect()&lt;/code&gt; on one real prompt from your app&lt;/li&gt;
&lt;li&gt;Write a 3-rule YAML that reflects your actual governance needs&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;policy.decide(request, findings)&lt;/code&gt; and log the full &lt;code&gt;PolicyDecision&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That four-step experiment is enough to understand whether &lt;code&gt;policyaware&lt;/code&gt; fits your stack.&lt;/p&gt;

&lt;p&gt;I am the author and sole maintainer of this package. I built it because every AI project I worked on had the same gap — no structured layer between raw user input and the model. If you run into anything unexpected, have a governance pattern not covered yet, or want to contribute, I want to hear from you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/ktirupati/policyaware" rel="noopener noreferrer"&gt;https://github.com/ktirupati/policyaware&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wiki &amp;amp; Docs:&lt;/strong&gt; &lt;a href="https://github.com/ktirupati/policyaware/wiki" rel="noopener noreferrer"&gt;https://github.com/ktirupati/policyaware/wiki&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this was useful, drop a like, share it with your team, and star the repo. Every bit of feedback helps make &lt;code&gt;policyaware&lt;/code&gt; better for everyone building serious AI systems in Python.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Built an AI Agent That Remembers My Entire Codebase (So I Don't Have To)</title>
      <dc:creator>KRISHNA KISHOR TIRUPATI</dc:creator>
      <pubDate>Tue, 28 Apr 2026 22:34:01 +0000</pubDate>
      <link>https://dev.to/ktirupati/i-built-an-ai-agent-that-remembers-my-entire-codebase-so-i-dont-have-to-2h32</link>
      <guid>https://dev.to/ktirupati/i-built-an-ai-agent-that-remembers-my-entire-codebase-so-i-dont-have-to-2h32</guid>
      <description>&lt;p&gt;Ever spent 20 minutes digging through a legacy module just to remember how a specific utility function handles null pointers? We've all been there. Modern codebases are growing at a rate that outpaces human memory. That's why I decided to build a "Second Brain" for my development workflow: a Retrieval-Augmented Generation (RAG) based AI Agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem: Context Switching is a Productivity Killer
&lt;/h3&gt;

&lt;p&gt;As developers, we spend more time reading code than writing it. When you're juggling microservices, custom hooks, and complex database schemas, the cognitive load becomes immense. I wanted something that didn't just "guess" based on general training data (looking at you, vanilla GPT-4), but actually &lt;strong&gt;knew&lt;/strong&gt; my specific implementation details.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Architecture: How It Works
&lt;/h3&gt;

&lt;p&gt;The core of this system is a RAG pipeline optimized for source code. Here’s the high-level flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ingestion:&lt;/strong&gt; A Python script crawls the repository, ignoring files in &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parsing:&lt;/strong&gt; It breaks the code into logical chunks (functions, classes, or modules).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedding:&lt;/strong&gt; These chunks are converted into vector representations using OpenAI's &lt;code&gt;text-embedding-3-small&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage:&lt;/strong&gt; The vectors are stored in a Pinecone database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieval:&lt;/strong&gt; When I ask a question, the agent finds the most relevant code snippets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning:&lt;/strong&gt; An LLM (GPT-4o) uses that retrieved context to provide a precise answer.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Show Me the Code!
&lt;/h3&gt;

&lt;p&gt;Here is a simplified version of the ingestion logic using &lt;code&gt;LangChain&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_community.document_loaders&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GenericLoader&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_community.document_loaders.parsers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LanguageParser&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_text_splitters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Language&lt;/span&gt;

&lt;span class="c1"&gt;# Load your local codebase
&lt;/span&gt;&lt;span class="n"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GenericLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./my-awesome-project&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;**/*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;suffixes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.js&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;LanguageParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Language&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PYTHON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parser_threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Split and Embed (Simplified)
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAIEmbeddings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_community.vectorstores&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;

&lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAIEmbeddings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;vectorstore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why This is a Game Changer
&lt;/h3&gt;

&lt;p&gt;Since integrating this into my local CLI, I’ve noticed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instant Onboarding:&lt;/strong&gt; I can point it at a new library and ask "How is authentication handled?" and get a breakdown in seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Debugging:&lt;/strong&gt; I can paste an error trace and ask "Which part of our business logic could cause this?"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; It helps ensure I'm using existing patterns instead of reinventing the wheel.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Building an AI agent that remembers your codebase isn't about replacing the developer; it's about augmenting them. It removes the "grunt work" of searching and lets you focus on architectural decisions and problem-solving.&lt;/p&gt;

&lt;p&gt;Are you using any custom AI tools in your workflow? Let's discuss in the comments!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>machinelearning</category>
      <category>programming</category>
    </item>
    <item>
      <title>Vibe Coding in 2026: How AI Tools Like Cursor, Replit, Claude, and GitHub Copilot Are Changing the Way We Build Software</title>
      <dc:creator>KRISHNA KISHOR TIRUPATI</dc:creator>
      <pubDate>Mon, 27 Apr 2026 22:22:35 +0000</pubDate>
      <link>https://dev.to/ktirupati/vibe-coding-in-2026-how-ai-tools-like-cursor-replit-claude-and-github-copilot-are-changing-the-3c05</link>
      <guid>https://dev.to/ktirupati/vibe-coding-in-2026-how-ai-tools-like-cursor-replit-claude-and-github-copilot-are-changing-the-3c05</guid>
      <description>&lt;p&gt;Remember when writing code meant typing every line, every bracket, every semicolon? That world is fading fast. In 2026, we are living in what many call the era of vibe coding, where describing what you want in plain English can get you most of the way to working code.&lt;/p&gt;

&lt;p&gt;I have been building with these tools every day, and the shift is real. This is not about replacing developers. It is about changing how we work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Vibe Coding
&lt;/h2&gt;

&lt;p&gt;Vibe coding means you describe your intent in natural language, and the AI writes the implementation. You focus on the what and why, while the AI handles the how.&lt;/p&gt;

&lt;p&gt;Instead of writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;calculate_fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;calculate_fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You tell Cursor or Claude: Create a function that calculates the nth Fibonacci number using recursion.&lt;/p&gt;

&lt;p&gt;The AI writes it, you review it, you ship it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Main Players in 2026
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GitHub Copilot
&lt;/h3&gt;

&lt;p&gt;Copilot lives inside your editor. You type a comment, it suggests the next few lines. You accept, modify, or reject.&lt;/p&gt;

&lt;p&gt;It works in VS Code, JetBrains, Neovim. It is the most widely adopted tool because it fits into existing workflows without forcing you to change editors.&lt;/p&gt;

&lt;p&gt;Example workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Function to fetch user data from API and cache it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copilot suggests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`user-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You review it. Maybe you change the cache TTL. Maybe you add error handling. But the structure is there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cursor
&lt;/h3&gt;

&lt;p&gt;Cursor is an AI-first editor built on VS Code. It understands your entire codebase, not just the file you are editing.&lt;/p&gt;

&lt;p&gt;You can ask it: Find everywhere we are making API calls without proper error handling.&lt;/p&gt;

&lt;p&gt;It scans your repo, shows you every instance, and can fix them all at once.&lt;/p&gt;

&lt;p&gt;Cursor has two modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat mode for asking questions&lt;/li&gt;
&lt;li&gt;Composer mode for making changes across multiple files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I use Cursor when I need to refactor or when I am working on a feature that touches many files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude and ChatGPT
&lt;/h3&gt;

&lt;p&gt;These are not IDEs. They are reasoning engines.&lt;/p&gt;

&lt;p&gt;You paste your code, describe the problem, and they help you debug, refactor, or architect.&lt;/p&gt;

&lt;p&gt;They excel at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explaining complex code&lt;/li&gt;
&lt;li&gt;Suggesting architectural improvements&lt;/li&gt;
&lt;li&gt;Writing test cases&lt;/li&gt;
&lt;li&gt;Converting code between languages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
You: This Python script is slow when processing large CSV files. How can I optimize it?&lt;/p&gt;

&lt;p&gt;Claude analyzes your code and suggests using pandas chunking, multiprocessing, or switching to Polars.&lt;/p&gt;
&lt;h3&gt;
  
  
  Replit
&lt;/h3&gt;

&lt;p&gt;Replit is a browser-based IDE with AI built in. You can go from idea to deployed app without leaving the browser.&lt;/p&gt;

&lt;p&gt;It is especially good for prototypes, learning, and small projects where you do not want to set up a local environment.&lt;/p&gt;
&lt;h2&gt;
  
  
  Real Architecture Example
&lt;/h2&gt;

&lt;p&gt;Let me show you how I built a real feature using vibe coding.&lt;/p&gt;

&lt;p&gt;Task: Add a rate limiter to our API endpoints.&lt;/p&gt;

&lt;p&gt;Here is how the conversation with Cursor went:&lt;/p&gt;

&lt;p&gt;Me: I need to add rate limiting to all our Express routes. Use Redis for storage. Limit to 100 requests per minute per IP.&lt;/p&gt;

&lt;p&gt;Cursor generated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rateLimiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`ratelimit:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;incr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Too many requests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rateLimiter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I asked: Add logging for when users hit the limit.&lt;/p&gt;

&lt;p&gt;It updated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Rate limit exceeded for IP: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Too many requests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;retryAfter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Final step: Apply this to all routes.&lt;/p&gt;

&lt;p&gt;Cursor modified the main app file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rateLimiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./middleware/rateLimiter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rateLimiter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Total time: 3 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture of AI Coding Tools
&lt;/h2&gt;

&lt;p&gt;Here is how these systems work under the hood:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────┐
│                    Your Editor/IDE                      │
│  (VS Code, Cursor, Replit)                             │
└────────────┬────────────────────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────────────────────┐
│              AI Coding Assistant Plugin                 │
│  • Captures your code context                          │
│  • Sends prompts + context to AI                       │
│  • Receives suggestions                                │
└────────────┬────────────────────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────────────────────┐
│                   AI Model Layer                        │
│  (GPT-4, Claude, Codex)                                │
│  • Processes code context                              │
│  • Generates suggestions                               │
│  • Returns formatted code                              │
└────────────┬────────────────────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────────────────────┐
│                  Your Codebase                          │
│  • Changes applied                                      │
│  • Context updated                                      │
│  • Ready for next iteration                            │
└─────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key is context. The more the AI knows about your project, the better its suggestions.&lt;/p&gt;

&lt;p&gt;Cursor indexes your entire repo. GitHub Copilot looks at open files and recent edits. Claude works with what you paste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow Example: Building a REST API
&lt;/h2&gt;

&lt;p&gt;Let me walk through building a simple REST API for a task manager using vibe coding.&lt;/p&gt;

&lt;p&gt;Step 1: Define the structure&lt;/p&gt;

&lt;p&gt;Me to Cursor: Create an Express API with routes for creating, reading, updating, and deleting tasks. Use MongoDB for storage.&lt;/p&gt;

&lt;p&gt;Cursor generates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongoose&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;taskSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;taskSchema&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tasks/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByIdAndUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;new&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tasks/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByIdAndDelete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Task deleted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb://localhost/taskmanager&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 2: Add error handling&lt;/p&gt;

&lt;p&gt;Me: Add try-catch blocks and proper error responses.&lt;/p&gt;

&lt;p&gt;Cursor updates all routes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tasks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 3: Add validation&lt;/p&gt;

&lt;p&gt;Me: Validate that title is required and completed defaults to false.&lt;/p&gt;

&lt;p&gt;Cursor modifies the schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;taskSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Total development time: under 10 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Data Flow
&lt;/h2&gt;

&lt;p&gt;Here is how data moves through a vibe coding session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developer Intent
      |
      v
  Natural Language Prompt
      |
      v
  AI Model (with code context)
      |
      v
  Generated Code Suggestion
      |
      v
  Developer Review &amp;amp; Edit
      |
      v
  Final Implementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What Works Best
&lt;/h2&gt;

&lt;p&gt;After months of daily use, here is what I have learned:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Be specific in your prompts&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bad: Make this faster&lt;/li&gt;
&lt;li&gt;Good: Optimize this loop using a hash map instead of nested iteration&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Give context&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of: Write a login function&lt;/li&gt;
&lt;li&gt;Say: Write a login function that checks credentials against our PostgreSQL users table, returns a JWT token, and logs failed attempts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Iterate in small steps&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do not ask for an entire feature at once&lt;/li&gt;
&lt;li&gt;Build piece by piece, testing as you go&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Review everything&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI makes mistakes&lt;/li&gt;
&lt;li&gt;It might use deprecated methods&lt;/li&gt;
&lt;li&gt;It might miss edge cases&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Limits
&lt;/h2&gt;

&lt;p&gt;Vibe coding is not magic. It struggles with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complex business logic that requires domain expertise&lt;/li&gt;
&lt;li&gt;Performance optimization for specialized use cases&lt;/li&gt;
&lt;li&gt;Architectural decisions that involve tradeoffs&lt;/li&gt;
&lt;li&gt;Debugging production issues that need deep system knowledge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You still need to understand what the code does. You still need to think like an engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Setup
&lt;/h2&gt;

&lt;p&gt;Here is my current workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cursor for feature development and refactoring&lt;/li&gt;
&lt;li&gt;GitHub Copilot for autocomplete while editing&lt;/li&gt;
&lt;li&gt;Claude for architecture discussions and code review&lt;/li&gt;
&lt;li&gt;Replit for quick prototypes and experiments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I spend less time typing, more time thinking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Vibe coding is not replacing developers. It is changing what we focus on.&lt;/p&gt;

&lt;p&gt;Instead of remembering syntax, we think about architecture.&lt;br&gt;
Instead of writing boilerplate, we design systems.&lt;br&gt;
Instead of debugging typos, we solve real problems.&lt;/p&gt;

&lt;p&gt;The tools are here. The question is: are you using them?&lt;/p&gt;

&lt;p&gt;What has your experience been with these AI coding tools? Are you skeptical, excited, somewhere in between? Let me know in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>github</category>
      <category>programming</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Designing and Deploying Agentic AI Systems in Production Using Azure OpenAI</title>
      <dc:creator>KRISHNA KISHOR TIRUPATI</dc:creator>
      <pubDate>Sun, 26 Apr 2026 02:27:32 +0000</pubDate>
      <link>https://dev.to/ktirupati/designing-and-deploying-agentic-ai-systems-in-production-using-azure-openai-1iaj</link>
      <guid>https://dev.to/ktirupati/designing-and-deploying-agentic-ai-systems-in-production-using-azure-openai-1iaj</guid>
      <description>&lt;p&gt;Designing and deploying agentic AI systems on Azure OpenAI is ultimately a software engineering problem, not just a prompt engineering exercise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Agentic AI on Azure OpenAI combines large language models with tools, memory, and orchestration so systems can perceive context, reason about goals, and act through APIs or workflows. In enterprise environments, these agents sit inside existing architectures, integrate with business systems like CRMs or ERPs, and must meet stringent requirements for reliability, security, observability, and governance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;At a high level, an Azure OpenAI agent in production is a composition of model, orchestration layer, enterprise services, and platform capabilities from Azure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typical Layers
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Experience Layer&lt;/strong&gt;&lt;br&gt;
This includes chat widgets, web and mobile apps, IVR, or line-of-business front ends that capture user inputs and display responses. They communicate with a backend agent API over HTTPS and often stream partial responses for better perceived latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Orchestration and Agent Runtime&lt;/strong&gt;&lt;br&gt;
This is usually implemented as a microservice or set of services running on Azure Kubernetes Service, Azure Container Apps, or App Service. It handles dialogue state, calls Azure OpenAI for reasoning, invokes tools via function calling, manages retries, and applies business rules such as guardrails or approval workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Azure OpenAI Service&lt;/strong&gt;&lt;br&gt;
This provides deployed models such as GPT-4 class models, responses or chat APIs, function/tool calling, and system-level safety settings. You configure deployments per region and SKU, define capacity, and integrate them with your orchestration tier through the standard REST or Python/Java/.NET SDKs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Enterprise Tools and Data&lt;/strong&gt;&lt;br&gt;
Agents rely on tools that wrap internal systems: REST APIs, databases, search endpoints, and workflow engines. For retrieval augmented generation, you usually add Azure AI Search or vector indexes, while for workflow automation you integrate with Logic Apps, Power Automate, or internal microservices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Cross-Cutting Services&lt;/strong&gt;&lt;br&gt;
Governance, observability, and security come from services like Azure Monitor, Application Insights, Log Analytics, API Management, Key Vault, and Entra ID (Azure AD). These ensure authentication, authorization, quota management, rate limiting, metrics, tracing, and auditing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Components of an Azure OpenAI Agent
&lt;/h3&gt;

&lt;p&gt;An agent is more than a single prompt; it is usually composed of several cooperating elements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policy and Role Definition&lt;/strong&gt;&lt;br&gt;
The agent's role defines its scope, allowed tools, and tone via system prompts and configuration. You specify what it may do, what data it may touch, and which escalation paths it must follow for sensitive actions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory and Context&lt;/strong&gt;&lt;br&gt;
Short-term memory is the conversation history and state for the current session, while long-term memory comes from knowledge bases and logs. On Azure this is often implemented with Azure AI Search, Cosmos DB, or SQL, combined with embeddings produced by Azure OpenAI models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tooling Interface&lt;/strong&gt;&lt;br&gt;
Functions are exposed to the model using Azure OpenAI function or tool calling: you define function schemas, arguments, and natural-language descriptions, then let the model choose when to call each tool. The orchestration layer executes the selected tool, captures the results, and feeds them back to the model as messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Safety, Guardrails, and Filters&lt;/strong&gt;&lt;br&gt;
You apply content filters, allow/deny lists, and input/output validation before and after every model call. For high-risk domains, human-in-the-loop review and approval are added as explicit steps in the workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  How an Agent Behaves in Real Enterprise Scenarios
&lt;/h2&gt;

&lt;p&gt;In production, agent behavior is shaped by business rules, data access patterns, and organizational risk tolerance. Below are practical scenarios that show how this plays out with Azure OpenAI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support Automation&lt;/strong&gt;&lt;br&gt;
A customer opens a support chat in a portal. The frontend sends the message to an agent API that enriches it with user profile data and recent tickets from a CRM tool. The agent uses Azure AI Search to retrieve relevant knowledge articles and internal runbooks, then asks Azure OpenAI to draft a response via the responses or chat API with function calling. If the issue exceeds certain risk thresholds, the agent routes the conversation to a human agent, attaching a summarized context and proposed reply for faster handling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision Support&lt;/strong&gt;&lt;br&gt;
A portfolio manager asks, "How will this product change impact our quarterly margin?" The orchestration layer calls financial and sales data APIs to fetch current numbers, then passes structured summaries to the model through tools. The agent runs scenario analysis through multiple calls: one to generate assumptions, one to compute summaries over metrics, and one to explain trade-offs in business language. Outputs include narrative explanation plus structured justification, which can be stored for audit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workflow Automation&lt;/strong&gt;&lt;br&gt;
An internal user requests, "Create a change request for updating this microservice and notify the owners." The agent uses tools to create a work item in Azure DevOps or ServiceNow, update a change calendar, and send notifications via email or Teams connectors. It returns a summary with links, IDs, and the steps it performed, giving transparency into actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  End-to-End Agent Workflow Example
&lt;/h2&gt;

&lt;p&gt;Consider a support automation agent deployed on Azure OpenAI and fronted by a web chat in a corporate portal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: User Request and Intake&lt;/strong&gt;&lt;br&gt;
The user types: "My invoice shows the wrong amount, can you fix it?" The frontend passes this text, session identifiers, and user ID to a backend API along with any client-side telemetry such as locale and device type. Basic validation, rate limiting, and authentication via Entra ID occur at API Management or the gateway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Context Assembly&lt;/strong&gt;&lt;br&gt;
The agent service fetches user profile details and recent invoices through internal APIs exposed as tools. It queries Azure AI Search using an embeddings-based index over billing policies and knowledge articles, returning several relevant passages. The service then constructs a prompt for Azure OpenAI that includes system instructions, conversation history, retrieved documents, and structured invoice data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Reasoning and Tool Selection&lt;/strong&gt;&lt;br&gt;
Using the responses or chat API with function calling enabled, the model decides that it must call a "get_invoice_details" tool because the user is referencing a specific invoice. The orchestration layer executes that tool by calling the billing service, then posts the result back as a tool response, prompting the model again. The model now checks for mismatched line items and determines that a partial credit is appropriate per policy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Action and Validation&lt;/strong&gt;&lt;br&gt;
The agent calls another tool, "create_credit_memo," but this time the orchestration code applies an extra guard: for credits above a certain amount, it requires human approval instead of automatic execution. The tool either executes or records the request in a queue for human review and returns the status to the agent. The orchestration layer logs all inputs, decisions, and tool outputs into Application Insights and Log Analytics for observability and audit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Response Generation and Streaming&lt;/strong&gt;&lt;br&gt;
The agent calls Azure OpenAI one more time with all updated context to generate a user-friendly explanation of what was done and what the user should expect next. Streaming is enabled so the frontend can display tokens as they arrive, which significantly improves perceived latency even if the overall response generation takes a few seconds. The final message is persisted to a conversation store along with structured metadata such as outcome status and tags for analytics.&lt;/p&gt;

&lt;p&gt;This pattern repeats across messages, giving the agent a dialog loop where each turn includes intake, context building, reasoning, tool use, and output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Approach on Azure OpenAI
&lt;/h2&gt;

&lt;p&gt;A robust agent implementation emerges from a staged approach that moves from problem definition to production hardening.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Defining the Use Case&lt;/strong&gt;&lt;br&gt;
Start with one or two focused journeys where agents can deliver measurable value, for example first-line support or internal request automation. Define clear success metrics such as deflection rate, handle time reduction, or user satisfaction, and translate them into model-level KPIs like answer accuracy or escalation rates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Designing Agent Workflows&lt;/strong&gt;&lt;br&gt;
Map the current process step by step, then identify which decisions can move to the agent and which must remain with humans. Translate this into an orchestration design that uses patterns such as sequential flows, concurrent calls, or handoff flows. For complex environments, adopt a multi-agent design where specialized agents handle retrieval, planning, or domain-specific tasks, coordinated by a higher-level controller.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt and Policy Engineering&lt;/strong&gt;&lt;br&gt;
Author precise system messages that describe role, boundaries, and tone, and include examples of desired behavior and red lines. Use few-shot examples for tricky reasoning steps, and add structured instructions that explain how to decide whether a tool is required. Encode non-negotiable business rules outside the prompt in actual code, so the agent can propose actions but cannot bypass compliance logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool Integration&lt;/strong&gt;&lt;br&gt;
Wrap each enterprise system in a well-typed function definition with clear names and human-readable descriptions that help the model choose correctly. Keep tool schemas small; large or rarely used tools can be loaded conditionally via a higher-level tool search step to keep the active tool set manageable. Implement timeouts, retries with backoff, and circuit breakers per tool to avoid cascading failures when downstream systems are slow or unavailable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment and Operations&lt;/strong&gt;&lt;br&gt;
Deploy the orchestration runtime to Azure Kubernetes Service or Azure Container Apps with proper horizontal scaling policies tied to CPU, memory, or QPS. Expose APIs through Azure API Management to control access, apply request throttling, and centralize authentication with Entra ID. Configure Azure Monitor, Application Insights, and Log Analytics for metrics, traces, and logs that capture every agent call, tool invocation, and error. For secrets and configuration such as API keys and connection strings, rely on Azure Key Vault and managed identities rather than environment variables or embedded secrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Challenges and How to Handle Them
&lt;/h2&gt;

&lt;p&gt;Putting agents into production surfaces a set of recurring engineering challenges that go beyond prompt tuning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reliability&lt;/strong&gt;&lt;br&gt;
API failures, timeouts, and model-side rate limits are common when systems operate at scale. You address this by using exponential backoff retries, circuit breakers, graceful degradation strategies, and careful quota management through Azure resource planning and API Management. For critical actions, implement idempotent operations and compensating transactions so repeated tool calls do not corrupt state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Latency&lt;/strong&gt;&lt;br&gt;
The main contributors to latency are network overhead, tool call cascades, and token generation within the model. Effective strategies include response streaming, reducing prompt and response length, batching where possible, and parallelizing independent tool calls. Model choice also matters: using smaller or more efficient deployments where appropriate can significantly improve latency and throughput.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost Management&lt;/strong&gt;&lt;br&gt;
Cost scales with total tokens and call volume, especially in multi-call agent workflows. You can control cost by pruning unnecessary context, compressing history into summaries, capping max tokens, and routing low-value traffic to cheaper models. Monitoring per-feature and per-tenant consumption and applying quotas ensures no single consumer overwhelms the budget.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debugging and Observability&lt;/strong&gt;&lt;br&gt;
Debugging agents is difficult because behavior emerges from prompts, model weights, tools, and data working together. Rich logging of prompts, tool calls, and outputs, combined with correlation IDs across services, makes it possible to replay problem sessions and iteratively refine prompts and workflows. Telemetry dashboards that track hallucination reports, escalation rates, tool error rates, and user feedback are essential to continuous improvement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;br&gt;
Scaling requires both the model side and the orchestration side to handle higher load with predictable performance. On the model side, that means provisioning sufficient capacity, using multiple deployments, and sometimes applying multi-region strategies for resilience. On the application side, it means stateless or externally stateful services, asynchronous processing for long-running actions, and autoscaling policies that respond to traffic patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Governance and Security&lt;/strong&gt;&lt;br&gt;
Enterprises need strong control over who can invoke agents, what data they can access, and how their actions are audited. Azure provides a foundation through Entra ID for identity, RBAC for resource access, private networking, and customer-managed keys for encryption at rest. You augment this with fine-grained policy at the application level, including role-based access to tools, PII redaction, data minimization, and retention controls. For regulated workloads, systematic logging and human-in-the-loop review for high-risk tasks provide additional assurance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Agentic AI on Azure OpenAI is most successful when treated as an engineered system that combines models, tools, data, and governance rather than a single intelligent component. By starting with clear use cases, designing explicit workflows, investing in observability and guardrails, and using Azure's platform capabilities for scaling and security, organizations can deploy agents that deliver meaningful automation and decision support while staying within enterprise risk boundaries.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>ai</category>
      <category>machinelearning</category>
      <category>openai</category>
    </item>
  </channel>
</rss>
