<?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: Tang Haoran</title>
    <description>The latest articles on DEV Community by Tang Haoran (@haorantang).</description>
    <link>https://dev.to/haorantang</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%2F4015038%2F4a7e5d79-1199-427d-8d15-c1ae6f45703e.png</url>
      <title>DEV Community: Tang Haoran</title>
      <link>https://dev.to/haorantang</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/haorantang"/>
    <language>en</language>
    <item>
      <title>Proving Your AI Agent Rules Hold for Every Input — Not Just the Ones You Tested</title>
      <dc:creator>Tang Haoran</dc:creator>
      <pubDate>Fri, 04 Sep 2026 04:21:39 +0000</pubDate>
      <link>https://dev.to/haorantang/proving-your-ai-agent-rules-hold-for-every-input-not-just-the-ones-you-tested-2984</link>
      <guid>https://dev.to/haorantang/proving-your-ai-agent-rules-hold-for-every-input-not-just-the-ones-you-tested-2984</guid>
      <description>&lt;h1&gt;
  
  
  Proving Your AI Agent Rules Hold for Every Input — Not Just the Ones You Tested
&lt;/h1&gt;

&lt;p&gt;Here's a question your auditors will eventually ask: &lt;strong&gt;"This decision the agent made — on what basis?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;LLMs are probabilistic. Ask twice, get two answers. If your enterprise delegates approvals, refunds, or access decisions to an agent and the only thing standing between it and a bad call is a prompt, you don't have governance — you have a probability distribution with a job title.&lt;/p&gt;

&lt;p&gt;The industry is converging on an answer: &lt;strong&gt;the LLM handles understanding; rules handle the verdict.&lt;/strong&gt; Put a deterministic rule engine in front of the model, and let it decide what the agent may and may not do, no matter what the model says.&lt;/p&gt;

&lt;p&gt;But here's the uncomfortable part: &lt;strong&gt;how do you know the rules themselves are deterministic?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most rule engines back that claim with unit tests. And unit tests prove exactly one thing: &lt;em&gt;the inputs you tested behave correctly&lt;/em&gt;. They say nothing about the inputs you didn't test.&lt;/p&gt;

&lt;p&gt;This post is about closing that gap — with three open-source projects that attack the problem at three different levels:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;The question it answers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Language&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.npmjs.com/package/@openoba/erdl" rel="noopener noreferrer"&gt;ERDL&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;"Can we express the rule unambiguously?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tests&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/OpenOBA/erdl-vectors" rel="noopener noreferrer"&gt;erdl-vectors&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;"Do independent implementations agree, byte for byte?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Proof&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/OpenOBA/erdl-formal" rel="noopener noreferrer"&gt;erdl-formal&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;"Does it hold for &lt;em&gt;every&lt;/em&gt; input?"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Together they move "deterministic" from a &lt;em&gt;claim&lt;/em&gt; to a &lt;em&gt;measurement&lt;/em&gt; — and, in the limit, to a &lt;em&gt;proof&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 1 — ERDL: a language where "deterministic" is the point
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@openoba/erdl" rel="noopener noreferrer"&gt;ERDL&lt;/a&gt; (Entity-Rule Definition Language) is a declarative rule format for AI agent behavior governance. The core idea is a &lt;code&gt;when → then&lt;/code&gt; decision expressed in plain YAML:&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;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;erdl/v2"&lt;/span&gt;
&lt;span class="na"&gt;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;2.1.0"&lt;/span&gt;
&lt;span class="na"&gt;metadata&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund-guard"&lt;/span&gt;
  &lt;span class="na"&gt;decision&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;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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SEC-001-refund-limit"&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&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;logic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AND&lt;/span&gt;
      &lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool.name"&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eq&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;issue_refund"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool.args.amount"&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gt&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
    &lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REQUEST_HUMAN&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Refund&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;over&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;5000,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;human&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;approval&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;required"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things make this different from "just YAML config":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A single semantic tree.&lt;/strong&gt; Every rule compiles to one of a &lt;strong&gt;34-node expression tree&lt;/strong&gt; — the &lt;em&gt;same&lt;/em&gt; tree whether you wrote it in the Simple projection (30 operators), the Expression projection, or a decision table. Three ways to &lt;em&gt;author&lt;/em&gt;; one way to &lt;em&gt;mean&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A precise evaluation semantics.&lt;/strong&gt; The tree is evaluated under a set of named constraints (E1–E12) that pin down the fuzzy parts of real-world rules: fixed-point decimal arithmetic for money (&lt;code&gt;scale=14&lt;/code&gt;, half-even rounding — so &lt;code&gt;0.1 + 0.2&lt;/code&gt; can't drift), three-valued logic for missing fields (a missing field folds to &lt;em&gt;false&lt;/em&gt;, so nothing fail-opens), empty-quantifier folding (&lt;code&gt;all([])&lt;/code&gt; is &lt;em&gt;false&lt;/em&gt;), and NFC string normalization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Auditable by construction.&lt;/strong&gt; Every evaluation produces a hashable, chainable &lt;strong&gt;Decision Object&lt;/strong&gt; — the audit record of &lt;em&gt;which rule fired, on what input, with what context&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The reference implementation ships as an npm package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loadErdlFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Evaluator&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@openoba/erdl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loadErdlFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;refund.erdl.yaml&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;result&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;Evaluator&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;issue_refund&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metadata.decision&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decision&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// 'REQUEST_HUMAN'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But a language is only as trustworthy as the claim "every implementation of it agrees." That's where the second layer comes in.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 2 — erdl-vectors: trust is measured, not endorsed
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/OpenOBA/erdl-vectors" rel="noopener noreferrer"&gt;erdl-vectors&lt;/a&gt; is a cross-implementation verification benchmark: &lt;strong&gt;301 frozen test vectors&lt;/strong&gt; that don't belong to any single implementation.&lt;/p&gt;

&lt;p&gt;The mechanism is deliberately adversarial to hand-waving:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A neutral spec.&lt;/strong&gt; Vectors are generated from the spec alone, with answers stored in a physically isolated file (&lt;code&gt;.gitignore&lt;/code&gt;d) so nobody can "pass" by reading the oracle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First-principles verification.&lt;/strong&gt; A runner must re-implement JCS (&lt;a href="https://www.rfc-editor.org/rfc/rfc8785" rel="noopener noreferrer"&gt;RFC 8785&lt;/a&gt;) and SHA-256 &lt;em&gt;from scratch&lt;/em&gt; — no &lt;code&gt;json-canonicalize&lt;/code&gt;, no SDK — then recompute every Decision Object hash byte-for-byte.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A canary for honesty.&lt;/strong&gt; One vector (K01) is generated by a &lt;em&gt;deliberately broken&lt;/em&gt; implementation. A correct runner must report it as a mismatch. A runner that skips independent recomputation and just echoes the expected answer gets caught on the spot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The audit layer (78 vectors) is now verified byte-for-byte by &lt;strong&gt;two independent third-party runners&lt;/strong&gt; — one in Go (&lt;a href="https://github.com/OpenOBA/erdl-vectors/blob/main/IMPLEMENTATIONS.md" rel="noopener noreferrer"&gt;norviq-go&lt;/a&gt;), one in Python (&lt;a href="https://github.com/OpenOBA/erdl-vectors/blob/main/IMPLEMENTATIONS.md" rel="noopener noreferrer"&gt;concordia-python&lt;/a&gt;, by Erik Newton of Concordia) — each matching &lt;strong&gt;107/107 canonical bytes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The principle behind all of this is captured in the repo's own line: &lt;strong&gt;"Neutrality isn't declared — it's measured."&lt;/strong&gt; The registry records &lt;em&gt;who, on what date, passed how many vectors&lt;/em&gt; — nothing more. Nobody gets an endorsement; the numbers speak for themselves.&lt;/p&gt;

&lt;p&gt;This matters because it answers the question "is the &lt;em&gt;spec&lt;/em&gt; right, or does the reference implementation just agree with its own generator?" Only when multiple &lt;em&gt;unrelated&lt;/em&gt; implementations, built from the spec text alone, converge byte-for-byte do you have evidence that the standard itself is sound.&lt;/p&gt;




&lt;h2&gt;
  
  
  Layer 3 — erdl-formal: from "tested" to "proven"
&lt;/h2&gt;

&lt;p&gt;Here's the thing about test vectors, even 301 of them: &lt;strong&gt;they are samples.&lt;/strong&gt; Vectors prove the cases you &lt;em&gt;chose&lt;/em&gt; to include. They can never prove the cases you &lt;em&gt;didn't&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/OpenOBA/erdl-formal" rel="noopener noreferrer"&gt;erdl-formal&lt;/a&gt; is the layer that closes that gap. It compiles ERDL's expression kernel into &lt;strong&gt;SMT&lt;/strong&gt; (via &lt;a href="https://github.com/Z3Prover/z3" rel="noopener noreferrer"&gt;Z3&lt;/a&gt;) and proves properties over &lt;strong&gt;all inputs&lt;/strong&gt; — not a sample, the entire space.&lt;/p&gt;

&lt;p&gt;A single assertion proves two things at once:&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;erdl_formal.field_contracts&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FieldContract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Schema&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;erdl_formal.properties&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;always_denies&lt;/span&gt;

&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FieldContract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file_cls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;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;int&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;FieldContract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;op_cls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;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;int&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# when: file_cls &amp;gt; op_cls  →  DENY
&lt;/span&gt;&lt;span class="n"&gt;rule&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;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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;field&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;file_cls&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;field&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;op_cls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;always_denies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;premises&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;file_cls&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;op_cls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                     &lt;span class="n"&gt;missing_field&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;op_cls&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;Behind that one line, Z3 searches the space of &lt;em&gt;all integers&lt;/em&gt; for a violating input. If it finds one, you get a &lt;strong&gt;concrete counterexample&lt;/strong&gt; you can replay against the real engine. If it finds none — &lt;code&gt;UNSAT&lt;/code&gt; — the property holds for &lt;strong&gt;every&lt;/strong&gt; input, and the proof is complete.&lt;/p&gt;

&lt;p&gt;What can it prove?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;never-errors&lt;/strong&gt; — evaluation never throws&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;always-denies&lt;/strong&gt; — hit means block (including &lt;em&gt;fail-closed&lt;/em&gt;: a missing field can't bypass the rule)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;always-allows / subsumption / equivalence / disjointness&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;override-soundness&lt;/strong&gt; — an &lt;code&gt;override&lt;/code&gt; can only relax DENY→ALLOW, never tighten toward a &lt;em&gt;less&lt;/em&gt; safe state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ring-respect&lt;/strong&gt; and &lt;strong&gt;emergency-shortcut&lt;/strong&gt; — ERDL-specific semantics that Cedar/OPA don't even model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The three "ERDL-specific" properties are the interesting ones: they're not generic policy properties, they're guarantees about &lt;em&gt;this&lt;/em&gt; language's money, time, aggregation, quantifier, and decision-object semantics — the parts that make ERDL an enterprise rules kernel rather than a generic policy DSL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A note on scope, because honesty builds trust:&lt;/strong&gt; erdl-formal proves the &lt;em&gt;expression kernel&lt;/em&gt; — the full 34-node tree and the E1–E12 constraints. Document structure, gloss rendering, and integration patterns are covered by the vectors and by engineering verification, not by SMT. It's a precise claim, and the precision is what makes it worth something.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why all three — and not just the proof?
&lt;/h2&gt;

&lt;p&gt;Because they answer &lt;em&gt;different&lt;/em&gt; questions, and each one makes the next credible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ERDL&lt;/strong&gt; gives the language a canonical meaning — without it, there's nothing to prove &lt;em&gt;about&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;erdl-vectors&lt;/strong&gt; proves that meaning is &lt;em&gt;reproducible&lt;/em&gt; — that independent implementations, from the spec alone, converge byte-for-byte.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;erdl-formal&lt;/strong&gt; proves that meaning is &lt;em&gt;safe&lt;/em&gt; — that the semantics hold over all inputs, not just the sampled ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A language without vectors is "trust my implementation." Vectors without a language are just a benchmark for something no one uses. Proof without vectors is a proof of a semantics &lt;em&gt;only you&lt;/em&gt; implemented — which is a proof about your code, not the standard.&lt;/p&gt;

&lt;p&gt;Layered together, they're the difference between "our rules engine is deterministic" (a claim) and "here is the language, here is the byte-for-byte agreement, here is the proof" (an audit trail).&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters now: A2A is coming
&lt;/h2&gt;

&lt;p&gt;The urgency isn't just about single agents. As agent-to-agent (A2A) protocols grow, agents will start &lt;em&gt;delegating decisions to each other&lt;/em&gt; — one agent approves, another acts, a third records. In that world, cross-implementation trust can't rest on bilateral agreements between vendors. It has to rest on something any independent party can verify.&lt;/p&gt;

&lt;p&gt;That's the standardization path this stack is built for: &lt;strong&gt;three independent implementations, one open spec, no single owner.&lt;/strong&gt; Every new independent runner is a brick in the trust infrastructure for the agent economy.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ERDL engine&lt;/strong&gt; — &lt;code&gt;npm install @openoba/erdl&lt;/code&gt; · &lt;a href="https://github.com/OpenOBA/erdl-landing/blob/main/erdl-spec.en.md" rel="noopener noreferrer"&gt;spec&lt;/a&gt; · MIT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;erdl-formal&lt;/strong&gt; — &lt;code&gt;pip install erdl-formal&lt;/code&gt; · &lt;a href="https://github.com/OpenOBA/erdl-formal" rel="noopener noreferrer"&gt;repo&lt;/a&gt; · Apache-2.0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;erdl-vectors&lt;/strong&gt; — &lt;a href="https://github.com/OpenOBA/erdl-vectors" rel="noopener noreferrer"&gt;repo&lt;/a&gt; · Apache-2.0 · &lt;strong&gt;open call for independent runners&lt;/strong&gt;: implement JCS + SHA-256 from the spec, verify all 78 audit vectors, and get recorded in the registry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 223 expression-layer vectors are still waiting for their first independent runner. If you want to &lt;em&gt;prove&lt;/em&gt; a standard rather than endorse one — the repo is open.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Determinism isn't declared. It's tested. And in the limit, it's proven.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aiagents</category>
      <category>governance</category>
      <category>security</category>
    </item>
    <item>
      <title>rulsynor-core v1.0: An AI Agent You Can Audit</title>
      <dc:creator>Tang Haoran</dc:creator>
      <pubDate>Sat, 08 Aug 2026 06:51:27 +0000</pubDate>
      <link>https://dev.to/haorantang/rulsynor-core-v10-an-ai-agent-you-can-audit-oie</link>
      <guid>https://dev.to/haorantang/rulsynor-core-v10-an-ai-agent-you-can-audit-oie</guid>
      <description>&lt;h1&gt;
  
  
  rulsynor-core v1.0: An AI Agent You Can Audit
&lt;/h1&gt;

&lt;p&gt;How do you trust an AI Agent in production? Not "trust" as in &lt;em&gt;I think it'll do the right thing&lt;/em&gt;. Trust as in &lt;strong&gt;cryptographic proof&lt;/strong&gt; that every decision was correct, traceable, and independently verifiable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Today: &lt;strong&gt;rulsynor-core&lt;/strong&gt; — open-source Guard engine for AI Agents. MIT license. On npm.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  30-Second Demo
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
bash
npx @openoba/rulsynor-core --tool=exec --cmd="rm -rf /"
🛡️ Decision: DENY
📝 Reason: Destructive command blocked.
🧾 Recorded: sha256:8274b0... (tamper-evident)
🧭 Alternative: Use the read tool to inspect first.
Not just "no." The agent learns why and what to do instead.

What It Does
Guard: Evaluates every tool call before execution — ring-sorted, sub-millisecond. 30 preset rules + write your own.
Audit: Every decision produces a 25-field cryptographic record. JCS + SHA-256. Chain-linked.
Verify: Anyone can verify audit records with zero SDK. Just JCS + SHA-256. No rulsynor needed.
What Makes It Different
Most AI safety tools are prompt-based. "Be careful" isn't governance. rulsynor-core gives you:

7 decision types — ALLOW, DENY, CORRECT, QUARANTINE, REQUEST_HUMAN, NOTIFY, EMERGENCY_HALT
Cryptographic audit chain — not "we logged it," mathematical proof
Third-party verified — 101 cross-implementation vectors, 13/13 passed by Concordia
MIT licensed — zero framework dependencies
Rules in Plain Language
复制
# "If the agent runs rm -rf, block it"
name: block-destructive-rm
when:
  conditions:
    - field: context.tool.name
      operator: eq, value: exec
    - field: context.tool.args.command
      operator: matches, value: rm\s+-rf
then:
  decision: DENY
  instruction: Destructive command blocked.
Any LLM can translate English descriptions into ERDL rules. The compiler validates everything before loading.

5-Minute Integration
import { Evaluator, GuardStateManager,
  loadPresetRules, toCompiledRules }
from '@openoba/rulsynor-core';

const rules = toCompiledRules(loadPresetRules());
const evaluator = new Evaluator(new GuardStateManager());

const result = evaluator.evaluate(
  { toolName, toolArgs, sessionId, agentId },
  rules
);
// result.decision → ALLOW | DENY | CORRECT | ...
Works with LangChain, MCP, custom ReAct loops. Same API everywhere.

Roadmap
 30 preset rules, 20 operators
 JCS+SHA-256 audit trail
 Third-party verified
 LangGraph integration guide
 Community rule marketplace
GitHub · npm

"LLM vendors deliver exceptional intelligence. We deliver accountability."

Built at OpenOBA. MIT.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>typescript</category>
      <category>security</category>
    </item>
    <item>
      <title>I proposed a rules layer for the A2A protocol. Here's why.</title>
      <dc:creator>Tang Haoran</dc:creator>
      <pubDate>Sun, 05 Jul 2026 13:04:42 +0000</pubDate>
      <link>https://dev.to/haorantang/i-proposed-a-rules-layer-for-the-a2a-protocol-heres-why-4op5</link>
      <guid>https://dev.to/haorantang/i-proposed-a-rules-layer-for-the-a2a-protocol-heres-why-4op5</guid>
      <description>&lt;p&gt;The AI agent protocol stack is taking shape fast. Two standards are now widely adopted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP&lt;/strong&gt; (Anthropic → Linux Foundation): Agent ↔ Tools. 97M+ monthly downloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A2A&lt;/strong&gt; (Google → Linux Foundation): Agent ↔ Agent. 150+ organizations in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are solid protocols. But they expose a question that every engineer deploying agents hits eventually:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who decides what an agent &lt;em&gt;shouldn't&lt;/em&gt; do?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The current answer: Prompts
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a responsible agent. Do not execute dangerous commands.
Follow security policies. Respect data boundaries.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any engineer who's actually deployed an agent knows how this ends. The prompt is a suggestion. The LLM is a probability engine. It doesn't understand "forbidden" — it understands "low probability."&lt;/p&gt;

&lt;p&gt;That's fine for a chatbot. It's not fine for banking, healthcare, or production infrastructure.&lt;/p&gt;

&lt;p&gt;What's needed is a mechanism that sits &lt;em&gt;before&lt;/em&gt; the tool call and says "no" deterministically — not as an LLM judgment, but as a protocol-level enforcement.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I proposed in the A2A community
&lt;/h2&gt;

&lt;p&gt;Last week, I opened a discussion on the A2A repo (&lt;a href="https://github.com/a2aproject/A2A/discussions/2031" rel="noopener noreferrer"&gt;#2031&lt;/a&gt;) proposing an extension to the Agent Card: a way for agents to &lt;em&gt;declare their behavioral rules&lt;/em&gt; at the protocol level.&lt;/p&gt;

&lt;p&gt;The reactions confirmed what I suspected: this is a real gap.&lt;/p&gt;

&lt;p&gt;A respected contributor from the community (&lt;a href="https://github.com/chopmob-cloud" rel="noopener noreferrer"&gt;chopmob-cloud / AlgoVoi&lt;/a&gt;) responded with a sharp distinction that materially improved the proposal: &lt;strong&gt;a trust score is reputation, but compliance requires evidence.&lt;/strong&gt; A number like 850 says "this agent is generally trusted." A recomputable, content-addressed record — &lt;code&gt;hash(rule_version + inputs + verdict)&lt;/code&gt; — says "this specific decision was permitted, and you can verify it yourself with no keys and no issuer contact."&lt;/p&gt;

&lt;p&gt;That distinction is now baked into the spec. Reputation scores are advisory. Compliance is per-decision, recomputable, no-trust-required.&lt;/p&gt;




&lt;h2&gt;
  
  
  ERDL in 30 seconds
&lt;/h2&gt;

&lt;p&gt;ERDL (Entity-Rule Definition Language) is a declarative rules standard. One YAML file. Placed in the agent's workspace. Evaluated by a deterministic engine before every tool call.&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;# agent.erdl.yaml&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no-dangerous-commands"&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&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;logic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AND&lt;/span&gt;
      &lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool.name"&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eq&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exec"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool.args.command"&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;match&lt;/span&gt;
          &lt;span class="na"&gt;value&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|format|drop&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;table)"&lt;/span&gt;
    &lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;BLOCK&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Dangerous&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;command&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;intercepted"&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="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required-human-approval"&lt;/span&gt;
    &lt;span class="na"&gt;priority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;45&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;logic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AND&lt;/span&gt;
      &lt;span class="na"&gt;conditions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action.impact_tier"&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gte&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;field&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action.domain"&lt;/span&gt;
          &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;in&lt;/span&gt;
          &lt;span class="na"&gt;value&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;employment"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;credit"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;healthcare"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REQUEST_HUMAN&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;High-impact&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;decision&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;requires&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;human&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;approval"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent cannot bypass this. It's not a prompt. It's a gate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where ERDL fits
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A2A  (Google)   Agent ↔ Agent   Communication
ERDL (OpenOBA)  Rules &amp;amp; Governance   ← This
MCP  (Anthropic) Agent ↔ Tool   Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It doesn't replace either. It complements them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP says &lt;em&gt;what tools the agent can use&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;A2A says &lt;em&gt;who the agent can talk to&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;ERDL says &lt;em&gt;what the agent should and shouldn't do&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The evidence-first architecture
&lt;/h2&gt;

&lt;p&gt;This is the part I'm most proud of, and it came directly from community feedback.&lt;/p&gt;

&lt;p&gt;Every ERDL decision generates an evidence record:&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;rule_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no-dangerous-commands"&lt;/span&gt;
&lt;span class="na"&gt;rule_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.3.2&lt;/span&gt;
&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;tool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exec"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;command&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;table&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;users"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;eval_tree&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tool.name == "exec" → &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;command MATCH "(delete|format|drop table)" → &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AND → &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;verdict&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;BLOCK&lt;/span&gt;
&lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-07-05T09:23:11.452Z&lt;/span&gt;
&lt;span class="na"&gt;receipt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sha256(canonicalize(above))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any third party — a regulator, a partner, an auditor — can re-derive the receipt from the record alone. No keys, no issuer contact, no "trust me."&lt;/p&gt;

&lt;p&gt;This is the difference between saying "our agent is safe" and proving it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What we have so far
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Spec v1.0: English + Chinese, MIT license&lt;/li&gt;
&lt;li&gt;Reference implementation: &lt;code&gt;npm install @openoba/erdl&lt;/code&gt;, 197 tests, 0 failures&lt;/li&gt;
&lt;li&gt;Agent Card extension proposal: under active discussion on A2A #2031&lt;/li&gt;
&lt;li&gt;Landing page: &lt;a href="https://openoba.github.io/erdl-landing" rel="noopener noreferrer"&gt;openoba.github.io/erdl-landing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What we need
&lt;/h2&gt;

&lt;p&gt;This isn't a solo project. A protocol standard only works if people use it, critique it, and contribute to it.&lt;/p&gt;

&lt;p&gt;If you've deployed AI agents and hit the "how do I stop it from doing X" problem — I'd love to hear about your experience. What guardrails did you build? What broke?&lt;/p&gt;

&lt;p&gt;If you think a rules layer in the agent protocol stack makes sense — or doesn't — I'd welcome the debate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/openoba/erdl" rel="noopener noreferrer"&gt;github.com/openoba/erdl&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;A2A Discussion&lt;/strong&gt;: &lt;a href="https://github.com/a2aproject/A2A/discussions/2031" rel="noopener noreferrer"&gt;RFC #2031&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Contact&lt;/strong&gt;: &lt;a href="mailto:support@openoba.com"&gt;support@openoba.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Posted by haoran-tang-ch · OpenOBA&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>machinelearning</category>
      <category>llm</category>
    </item>
    <item>
      <title>The AI Agent Protocol Stack is Missing a Layer — Here's the Third One</title>
      <dc:creator>Tang Haoran</dc:creator>
      <pubDate>Sat, 04 Jul 2026 13:07:10 +0000</pubDate>
      <link>https://dev.to/haorantang/the-ai-agent-protocol-stack-is-missing-a-layer-heres-the-third-one-26fh</link>
      <guid>https://dev.to/haorantang/the-ai-agent-protocol-stack-is-missing-a-layer-heres-the-third-one-26fh</guid>
      <description>&lt;p&gt;MCP connects agents to tools. A2A connects agents to agents. Both are excellent. Neither answers one question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do agents know what they're ALLOWED to do?&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Cisco Research proposed a layered agent protocol architecture in 2025 (arXiv:2511.19699):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;L8&lt;/strong&gt; (Agent Communication Layer) → Standardized message envelopes, speech-act performatives&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L9&lt;/strong&gt; (Agent Semantic Negotiation Layer) → &lt;em&gt;"does not exist today"&lt;/em&gt; (direct quote from the paper)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;L8 is being implemented by MCP and A2A. &lt;strong&gt;L9 had no answer — until now.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  ERDL: The Third Layer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Entity-Rule Definition Language&lt;/strong&gt; is an open standard for agent behavioral rules. It sits between the agent's reasoning and its tool execution:&lt;/p&gt;

&lt;p&gt;MCP → tools. A2A → communication. ERDL → rules.&lt;/p&gt;

&lt;p&gt;Three layers. One complete agent protocol stack.&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%2Fopenoba.github.io%2Ferdl-landing%2Fstack.html" 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%2Fopenoba.github.io%2Ferdl-landing%2Fstack.html" alt="Agent Protocol Stack" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What ERDL brings
&lt;/h3&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;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;11 operators including &lt;code&gt;within&lt;/code&gt; and &lt;code&gt;rate&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16 deterministic action types&lt;/td&gt;
&lt;td&gt;Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution Rings (Ring 0–3)&lt;/td&gt;
&lt;td&gt;Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Guardian Agent model&lt;/td&gt;
&lt;td&gt;Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SafeExpr engine (zero code injection)&lt;/td&gt;
&lt;td&gt;Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hot reload without restart&lt;/td&gt;
&lt;td&gt;Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Structured audit trails&lt;/td&gt;
&lt;td&gt;Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snapshot + rollback&lt;/td&gt;
&lt;td&gt;Complete&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
yaml
rule: block_privileged_commands
priority: 0
description: "Block dangerous shell commands"
when:
  field: "tool.command"
  operator: in
  value: ["sudo", "rm -rf"]
then:
  action: BLOCK
  message: "Privileged commands require human approval"
**One YAML file. When an agent tries to call a blocked tool, ERDL's Action Guard intercepts the call before it reaches the tool. Not after. Not as a suggestion. The engine evaluates conditions, matches rules, and returns a deterministic verdict.

The agent never touches sudo. Period.

OWASP Top 10 (2026) — How ERDL Maps
OWASP Risk  ERDL Mitigation
R1: Excessive Agency    Time windows + rate limiting
R2: Prompt Injection    Guard rules run before LLM output
R3: Supply Chain    Agent BOM with rule audit trail
R4: Data Leakage    Field-level BLOCK rules
R5: Overreliance    Guardian Agent oversight
R6: Multi-Agent Collusion   Cross-agent audit chains
EU AI Act (effective August 2, 2026)
ERDL maps directly to transparency and human oversight requirements. Audit records export to OCSF format, compatible with SIEM systems.

The Stack is Now Complete
MCP — tools (Anthropic, Linux Foundation)
A2A — communication (Google, Linux Foundation)
ERDL — rules (OpenOBA, MIT)
Landing Page: openoba.github.io/erdl-landing
Spec v1.0 (English): spec/index-en.md
GitHub: github.com/OpenOBA/ERDL
MIT License. RFC open.

What do you think — does the agent protocol stack need a dedicated rules layer? Let's discuss.**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>security</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
