<?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: Emek Can Doğru</title>
    <description>The latest articles on DEV Community by Emek Can Doğru (@dogrucanemekalt).</description>
    <link>https://dev.to/dogrucanemekalt</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%2F4130532%2F0c40f603-a75a-4c36-b21c-311f391f4d66.png</url>
      <title>DEV Community: Emek Can Doğru</title>
      <link>https://dev.to/dogrucanemekalt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dogrucanemekalt"/>
    <language>en</language>
    <item>
      <title>"The boss said yes" is not an approval</title>
      <dc:creator>Emek Can Doğru</dc:creator>
      <pubDate>Thu, 08 Oct 2026 18:27:58 +0000</pubDate>
      <link>https://dev.to/dogrucanemekalt/the-boss-said-yes-is-not-an-approval-39kn</link>
      <guid>https://dev.to/dogrucanemekalt/the-boss-said-yes-is-not-an-approval-39kn</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/tV2ZTazaY3k" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;"The boss said yes" is not an approval.&lt;/p&gt;

&lt;p&gt;When an AI agent wants to spend money through Verax, the call is held. The agent cannot approve it by itself; there is no auto-approve path. A person approves it, on the machine where the body runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What gets held
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;spend&lt;/code&gt; is capped by payee, amount, currency and a daily limit, and even inside those caps it always defers. Any other call is held when your policy marks its rule for approval. The agent's token can read and write memory through the gate; it cannot approve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who resolves it
&lt;/h2&gt;

&lt;p&gt;A held call is resolved with &lt;code&gt;verax approve&lt;/code&gt; on that machine. There is no remote approver. When four approvals of the same request arrive at once, one allow is recorded and the others answer &lt;code&gt;already-resolved&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A spend approval also re-checks the daily budget at the moment it is approved, against what has already been approved today, so approvals that are each fine on their own cannot add up past the limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The name in the record
&lt;/h2&gt;

&lt;p&gt;The approval is not just a click. The approver's operator id is bound into the signed record, so a week later "who approved this?" has an answer you can check, not one you have to remember.&lt;/p&gt;

&lt;p&gt;Since 0.4.2 an approval sent over HTTP needs a passkey assertion when an operator is registered, and &lt;code&gt;verax verify&lt;/code&gt; checks that signature against the operator's public key without asking the body. The panel that sends it opens through &lt;code&gt;verax desktop&lt;/code&gt;, which is not released yet, so on a released install the approval is &lt;code&gt;verax approve&lt;/code&gt;, and a CLI approval stays unsigned: the operator id is in the record the body signs.&lt;/p&gt;

&lt;p&gt;What it doesn't do: approving is not paying. Verax records an authorization; a person or another system moves the money. The operator id is the id Verax knows that operator by, not a verified identity from your company directory. Since 0.4.3 a checkpoint can be registered with a transparency log someone else runs; without that, the same system keeps the record and signs it. No independent audit has been done.&lt;/p&gt;

&lt;p&gt;Episode 4 of the series, animated in three.js and voiced with ElevenLabs.&lt;/p&gt;

&lt;p&gt;Source (Apache-2.0): &lt;a href="https://github.com/verax-ai/verax" rel="noopener noreferrer"&gt;https://github.com/verax-ai/verax&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Pulling the red lever on an AI agent</title>
      <dc:creator>Emek Can Doğru</dc:creator>
      <pubDate>Sat, 03 Oct 2026 08:28:56 +0000</pubDate>
      <link>https://dev.to/dogrucanemekalt/pulling-the-red-lever-on-an-ai-agent-4bnn</link>
      <guid>https://dev.to/dogrucanemekalt/pulling-the-red-lever-on-an-ai-agent-4bnn</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/TkcL-EAcGV4" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Sometimes you want an AI agent to stop everything, right now.&lt;/p&gt;

&lt;p&gt;Verax has a halt switch for that. Once an operator pulls it, every call the agent makes after that point is refused, and each refusal is signed and recorded like any other decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who can pull it, and who can let go
&lt;/h2&gt;

&lt;p&gt;On an install the switch is the command line: &lt;code&gt;verax halt&lt;/code&gt;, and since 0.4.1 &lt;code&gt;verax resume&lt;/code&gt;. Behind them are two HTTP doors. &lt;code&gt;POST /api/halt&lt;/code&gt; accepts any operator session. &lt;code&gt;POST /api/resume&lt;/code&gt; needs &lt;code&gt;verax:approve&lt;/code&gt;. The agent's token carries neither, so the agent cannot stop itself to dodge a check, and it cannot lift a halt someone else set.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET /api/halt&lt;/code&gt; answers whether the body is halted and who halted it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The resume is written down first
&lt;/h2&gt;

&lt;p&gt;Who halted, who resumed and when go to &lt;code&gt;halt-history.jsonl&lt;/code&gt;, a file next to the switch. The resume line is written before the halt is lifted. If that line cannot be written, the body stays halted.&lt;/p&gt;

&lt;p&gt;That file is a plain log, not a signed one. Since 0.4.2 each halt and resume is also written to the ledger as a control record signed by the body's record key, beside the signed refusals made while the switch is down, and &lt;code&gt;verax verify&lt;/code&gt; fails on any allow inside a halt window. The body signs that record, not the operator.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it doesn't do
&lt;/h2&gt;

&lt;p&gt;A call that is already running when the switch is pulled is not cut off. The switch stops everything after it.&lt;/p&gt;

&lt;p&gt;The halt is a file in this machine's state directory. It stops the body it sits next to, not one it cannot see.&lt;/p&gt;

&lt;p&gt;In the film the switch is a lever. On a released install it is the command line and those two doors; the panel that would carry a real button opens through &lt;code&gt;verax desktop&lt;/code&gt;, which is not released yet.&lt;/p&gt;

&lt;p&gt;Episode 3 of the series, animated in three.js and voiced with ElevenLabs.&lt;/p&gt;

&lt;p&gt;Source (Apache-2.0): &lt;a href="https://github.com/verax-ai/verax" rel="noopener noreferrer"&gt;https://github.com/verax-ai/verax&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>When there is no rule, the answer is no</title>
      <dc:creator>Emek Can Doğru</dc:creator>
      <pubDate>Wed, 30 Sep 2026 21:22:56 +0000</pubDate>
      <link>https://dev.to/dogrucanemekalt/when-there-is-no-rule-the-answer-is-no-5hdd</link>
      <guid>https://dev.to/dogrucanemekalt/when-there-is-no-rule-the-answer-is-no-5hdd</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/bL9KeqZX8k8" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;When an AI agent asks Verax for something there is no rule for, the answer is no. Nothing is allowed by default.&lt;/p&gt;

&lt;p&gt;That covers the obvious case, like an agent trying to export your customer list. It also covers a quieter one. The agent gets refused, then tries the same thing under a different tool name. A new name has no rule either, so it gets refused again.&lt;/p&gt;

&lt;h2&gt;
  
  
  What that looks like in the policy
&lt;/h2&gt;

&lt;p&gt;The policy Verax starts from names four tools and nothing else:&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;"version"&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;"default"&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;"rules"&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;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="s2"&gt;"memory-get"&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;"memory.get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"requires"&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;"verax:read"&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;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="s2"&gt;"memory-put"&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;"memory.put"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"requires"&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;"verax:memory"&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;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="s2"&gt;"audit-explain"&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;"audit.explain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"requires"&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;"verax:read"&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;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="s2"&gt;"message-read"&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;"message.read"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"requires"&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;"verax:read"&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;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;A call to anything else, including a tool that exists on a server attached behind Verax, is refused before that server sees it. Two rules for the same tool are refused when the policy loads, so a second rule cannot quietly widen the first.&lt;/p&gt;

&lt;h2&gt;
  
  
  A refusal is a record too
&lt;/h2&gt;

&lt;p&gt;Refusals are signed and recorded the same way approvals are: which agent, which tool, what time. When something goes wrong, the attempts that were stopped usually tell you more than the ones that went through.&lt;/p&gt;

&lt;p&gt;The record stays on your machine. &lt;code&gt;verax verify&lt;/code&gt; reads it with no server running and nothing on the network, and says how many signatures verify and whether the chain is unbroken.&lt;/p&gt;

&lt;p&gt;What it doesn't do: the same system keeps the record and signs it, and no independent audit has been done.&lt;/p&gt;

&lt;p&gt;Episode 2 of the series, animated in three.js and voiced with ElevenLabs.&lt;/p&gt;

&lt;p&gt;Source (Apache-2.0): &lt;a href="https://github.com/verax-ai/verax" rel="noopener noreferrer"&gt;https://github.com/verax-ai/verax&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>What an agent's tool call leaves behind</title>
      <dc:creator>Emek Can Doğru</dc:creator>
      <pubDate>Tue, 29 Sep 2026 17:43:27 +0000</pubDate>
      <link>https://dev.to/dogrucanemekalt/what-an-agents-tool-call-leaves-behind-3ela</link>
      <guid>https://dev.to/dogrucanemekalt/what-an-agents-tool-call-leaves-behind-3ela</guid>
      <description>&lt;p&gt;Ask an AI agent to do something with real consequences, and the question comes later: who allowed that? Most setups can tell you what the agent did. Fewer can tell you which rule let it happen, and almost none keep a record of what was refused.&lt;/p&gt;

&lt;p&gt;Verax is an MCP server that sits between an agent and its tools. I built it to answer that question with a file, not a guess.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/ev5FYkjxOLo" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every call passes a rule first.&lt;/strong&gt; Each &lt;code&gt;tools/call&lt;/code&gt; goes through a policy before anything runs. Nothing is allowed by default: a tool with no rule is refused. Renaming the tool doesn't help, because the new name has no rule either.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refusals are records too.&lt;/strong&gt; An allowed call and a refused call both leave a signed decision record: which agent, which tool, which rule, what time. When something goes wrong, the attempts that were stopped often say more than the ones that went through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Money waits for a person.&lt;/strong&gt; A spend always defers. The person approving sees a summary, and the approval names the request they saw. If the request changed after they looked, the approval doesn't go through. The agent's own token can't approve; approving is a separate scope it doesn't have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The record stays with you.&lt;/strong&gt; The ledger lives on the machine the server runs on. &lt;code&gt;verax verify&lt;/code&gt; reads it back without the server, and a one-cent change breaks the signature.&lt;/p&gt;

&lt;p&gt;Try it in a terminal (Node 22.6+):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @verax-ai/body demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It records an allowed memory write and read, a signed refusal of a message to a host off the policy list, and a payment held until you answer &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it doesn't do.&lt;/strong&gt; The policy sees the tool name and the token's scopes, not the argument text or what a tool returns, so it is not a prompt-injection filter. There is no independent audit yet; what is proven and what isn't is listed line by line in &lt;a href="https://github.com/verax-ai/verax/blob/main/docs/STATUS.md" rel="noopener noreferrer"&gt;docs/STATUS.md&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Break it.&lt;/strong&gt; Each valid break of the boundary between the agent's account and the approver pays USD 100, up to USD 500 in total. The terms are in &lt;a href="https://github.com/verax-ai/verax/blob/main/SECURITY.md" rel="noopener noreferrer"&gt;SECURITY.md&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The video above is the first of two one-minute animated episodes. The scenes are drawn in three.js and the voices are generated with ElevenLabs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repo: &lt;a href="https://github.com/verax-ai/verax?utm_source=devto&amp;amp;utm_medium=article" rel="noopener noreferrer"&gt;https://github.com/verax-ai/verax?utm_source=devto&amp;amp;utm_medium=article&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Site: &lt;a href="https://verax-ai.com/?utm_source=devto&amp;amp;utm_medium=article" rel="noopener noreferrer"&gt;https://verax-ai.com/?utm_source=devto&amp;amp;utm_medium=article&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The EU AI Act's logging rule moved to December 2027. The logs did not get easier.</title>
      <dc:creator>Emek Can Doğru</dc:creator>
      <pubDate>Thu, 17 Sep 2026 22:23:22 +0000</pubDate>
      <link>https://dev.to/dogrucanemekalt/the-eu-ai-acts-logging-rule-moved-to-december-2027-the-logs-did-not-get-easier-2eb8</link>
      <guid>https://dev.to/dogrucanemekalt/the-eu-ai-acts-logging-rule-moved-to-december-2027-the-logs-did-not-get-easier-2eb8</guid>
      <description>&lt;p&gt;The Digital Omnibus on AI (Regulation (EU) 2026/1744) was published in the Official Journal on 24 July 2026 and entered into force three days later. The obligations for high-risk AI systems, including record-keeping, now apply from 2 December 2027 for the stand-alone systems in Annex III and from 2 August 2028 for AI built into regulated products. If you read a post this summer that said "August 2026", that date is gone. The rule is not.&lt;/p&gt;

&lt;p&gt;Article 12 of the Act is short. A high-risk system must technically allow the automatic recording of events over its lifetime, and those records must be good enough to trace a situation that turned risky, to support monitoring after the system is on the market, and to follow how the system operates. That is the whole requirement, and it is a requirement about what the system can record, not about what a dashboard shows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why an agent's logs do not pass this today
&lt;/h2&gt;

&lt;p&gt;Most agent stacks log. Almost none of them keep records. The difference is what is missing from the line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Who asked.&lt;/strong&gt; A log line names a service account, not the agent, its scopes, or the human who was behind it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What was asked.&lt;/strong&gt; The prompt is there, the actual tool call with its arguments often is not, and nothing ties the two together.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which rule decided.&lt;/strong&gt; The line says the call ran. It does not say which policy, at which version, allowed it, or why a refused call was refused.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What happened.&lt;/strong&gt; The result is somewhere else, in another log, with another timestamp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Whether the line is still the original.&lt;/strong&gt; A text log can be edited, trimmed, or lost, and afterwards nobody can tell.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the logs sit in a vendor's cloud. When the question is asked, the answer belongs to someone else.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a record needs
&lt;/h2&gt;

&lt;p&gt;We ended up with five parts, and each one answers a question an auditor actually asks.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identity and scope.&lt;/strong&gt; The agent connects with a token, and the token names what it may do: read, memory, act, pay, approve, audit. No default token; the gate does not open until this is configured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The request.&lt;/strong&gt; A hash of the exact call, so the record and the call cannot drift apart.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The decision.&lt;/strong&gt; Allow, deny, or wait for a human, with the policy hash and a reason code. A refusal is written the same way as an approval; silence is not a record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The effect.&lt;/strong&gt; After the call runs, an effect row with the result hash, reconciled against the decision that allowed it. &lt;code&gt;audit.explain&lt;/code&gt; reads a decision back with its chain, its signatures and its findings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A signature and a chain.&lt;/strong&gt; Each record is signed, each carries the hash of the one before it, and a copy of the ledger is kept beside the original. &lt;code&gt;verax doctor&lt;/code&gt; says when the copy and the ledger disagree.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How Verax does it
&lt;/h2&gt;

&lt;p&gt;Verax is an open-source MCP server (Apache-2.0) that sits between an agent and its tools. Every tool call passes a policy gate and leaves a signed decision record before anything runs. Every call that ran leaves an effect row that is reconciled against its record afterwards. A call the policy will not decide alone is held until an operator on that machine approves it, from the panel or the command line. The ledger stays on the machine the body runs on, and the record does not leave it.&lt;/p&gt;

&lt;p&gt;A few things we had to build this week to make that hold under load, measured on one laptop with 150 agents over 30 days of synthetic traffic (200,000 decisions), and shipped in 0.1.2: the ledger is cut into pieces of 50,000 rows with a persistent ref index, so a restart reads the open piece and the index rather than every record ever written (1.9 s and 518 MB at 200k with both pieces closed); a day's window costs the day's rows, not the ledger's age; &lt;code&gt;verax doctor&lt;/code&gt; compares the evidence copy and the index to the pieces and says when they disagree. The same release closes six faults an outside review reproduced on the earlier code: parallel calls passing a rate limit, one ref running a tool more than once, a daily spend cap passed by parallel requests, one request approved more than once, a tenant's own memory record hidden by another tenant's, and a retry running on an approval after the token had lost its scope. Each has a guard now.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not do
&lt;/h2&gt;

&lt;p&gt;We keep this list on the website and it belongs here too. Today the same system keeps the record and signs it; a separate witness process exists, an independent one does not. There is no tenant boundary. On a single-copy ledger, silence cannot be told from nothing happening. Payloads sit in plaintext. No independent audit has been done. And whether a given deployment meets Article 12 is a conformity question for your assessor, not a claim we make.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;npm install -g @verax-ai/body&lt;/code&gt; (0.1.2, published with provenance from the repository), then &lt;code&gt;verax doctor&lt;/code&gt; names what the body still needs before it listens (Node 22.6 or newer). The entry in the official MCP Registry is &lt;code&gt;io.github.verax-ai/verax&lt;/code&gt;; the code is at &lt;a href="https://github.com/verax-ai/verax" rel="noopener noreferrer"&gt;https://github.com/verax-ai/verax&lt;/a&gt; and the site is &lt;a href="https://verax-ai.com" rel="noopener noreferrer"&gt;https://verax-ai.com&lt;/a&gt;. The free tier is the open-source install; the pilot is how companies run it with us. Questions and disagreements welcome in the comments; the record format is Cedulon's, and it is open too.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>compliance</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
