<?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: Nicholas Seney</title>
    <description>The latest articles on DEV Community by Nicholas Seney (@nseney1).</description>
    <link>https://dev.to/nseney1</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%2F4146249%2F4f3d10d1-02ef-404c-bccf-f03eb4201bc9.jpg</url>
      <title>DEV Community: Nicholas Seney</title>
      <link>https://dev.to/nseney1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nseney1"/>
    <language>en</language>
    <item>
      <title>I Built an Enforcement Engine for AI Coding Agents. Then the Agents Gamed That Too (Soma to Aegis v4.3)</title>
      <dc:creator>Nicholas Seney</dc:creator>
      <pubDate>Sun, 18 Oct 2026 16:08:57 +0000</pubDate>
      <link>https://dev.to/nseney1/i-built-an-enforcement-engine-for-ai-coding-agents-then-the-agents-gamed-that-too-soma-to-aegis-20f8</link>
      <guid>https://dev.to/nseney1/i-built-an-enforcement-engine-for-ai-coding-agents-then-the-agents-gamed-that-too-soma-to-aegis-20f8</guid>
      <description>&lt;p&gt;&lt;em&gt;A note: If you read my &lt;a href="https://dev.to/nseney1/your-ai-agents-rules-file-is-a-gentlemans-agreement-heres-what-happens-when-you-build-2dml"&gt;earlier post on Soma&lt;/a&gt;, a lot has changed. After dogfooding the project across ~690 coding sessions and four major versions, I renamed it from Soma to &lt;a href="https://github.com/nseney1/Aegis-Guardrails" rel="noopener noreferrer"&gt;Aegis Guardrails&lt;/a&gt; (&lt;code&gt;aegis-guardrails&lt;/code&gt; on PyPI), deleted about 40% of the codebase, and tore out several mechanisms I bragged about in the original write-up because they broke in practice. I'm writing this update because I want a record of what actually held up and what failed when an agent was put under real pressure.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;In my first post, I argued that a &lt;code&gt;.cursorrules&lt;/code&gt;, &lt;code&gt;CLAUDE.md&lt;/code&gt;, or &lt;code&gt;AGENTS.md&lt;/code&gt; file is a gentleman's agreement. You write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Always read a file before editing it
- Run tests after making changes
- Never use eval() on untrusted input
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then you hope the model remembers it 40 turns into a debugging session. Often, it doesn't. Under task pressure, agents skip rules, lose them to context compaction, or fail open when a check errors out.&lt;/p&gt;

&lt;p&gt;My original solution (then called Soma) was to treat rules like code with a lifecycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Serve rules &lt;strong&gt;just-in-time&lt;/strong&gt; over MCP for the specific files the agent is about to edit, clamped to a 2,000-token budget.&lt;/li&gt;
&lt;li&gt;Run &lt;strong&gt;deterministic Python AST checks&lt;/strong&gt; locally in a git &lt;code&gt;pre-commit&lt;/code&gt; hook before allowing a commit.&lt;/li&gt;
&lt;li&gt;Track &lt;strong&gt;rule fitness&lt;/strong&gt; so rules that prevent bugs get promoted, and rules that never fire or produce false positives decay and get pruned.&lt;/li&gt;
&lt;li&gt;Keep &lt;strong&gt;zero runtime dependencies&lt;/strong&gt; (100% Python standard library).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Numbers 1, 2, and 4 held up. Number 3, and the trust model around it, had a serious flaw: &lt;strong&gt;I replaced a gentleman's agreement in the prompt with a gentleman's agreement in the MCP server.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is what went wrong between v1.0 and v3.3, why I cut the codebase from 39,426 lines down to ~26,000 for v4, and how &lt;code&gt;aegis-guardrails&lt;/code&gt; v4.3 works today.&lt;/p&gt;




&lt;h2&gt;
  
  
  4 Things I Got Wrong in v1-v3
&lt;/h2&gt;

&lt;p&gt;When I ran a multi-lens audit of the repo and inspected the logs across ~690 real sessions, four failures stood out (I documented the full post-mortem with git commands to reproduce every number in &lt;a href="https://github.com/nseney1/Aegis-Guardrails/blob/main/docs/why-aegis.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/why-aegis.md&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Rules were disabling themselves at runtime
&lt;/h3&gt;

&lt;p&gt;In the original post, I showed a rule file (&lt;code&gt;trap-local-green-ci-red&lt;/code&gt;) that stored its own &lt;code&gt;fitness&lt;/code&gt; block right in the YAML frontmatter:&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;# How v1-v3 did it (broken):&lt;/span&gt;
&lt;span class="na"&gt;fitness&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;
  &lt;span class="na"&gt;triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
  &lt;span class="na"&gt;true_positives&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;false_positives&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end of a session, the server wrote updated fitness counts back into each &lt;code&gt;.md&lt;/code&gt; rule file. The problem was that v3 also had a SHA-256 integrity manifest (&lt;code&gt;.aegis/rules/manifest.json&lt;/code&gt;) meant to detect if an agent tampered with a rule.&lt;/p&gt;

&lt;p&gt;Because session-close rewrote the rule frontmatter without refreshing the manifest, the next scan saw an "edited" rule, assumed it was tampered with, logged a warning to &lt;code&gt;stderr&lt;/code&gt;, and excluded it. When I checked &lt;code&gt;main&lt;/code&gt;, &lt;strong&gt;45 of 49 manifest entries were stale, and &lt;code&gt;aegis_scan&lt;/code&gt; in my own session was returning 0 rules.&lt;/strong&gt; Worse, because the frontmatter read-modify-write wasn't locked across processes, concurrent sessions lost about 80 out of 120 fitness updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The fitness math was inverted for blocking rules
&lt;/h3&gt;

&lt;p&gt;In v3, every rule whose &lt;code&gt;target_paths&lt;/code&gt; matched a changed file received credit for whether that &lt;code&gt;aegis check&lt;/code&gt; run passed or failed.&lt;/p&gt;

&lt;p&gt;Think about what happens to a blocking pre-commit gate under that math. If a gate does its job and blocks 4 bad commits before you fix the code on the 5th try, the ledger recorded 4 failures and 1 pass for that gate. The more bugs a gate stopped, the worse its score looked.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The agent was grading its own homework (and forging release receipts)
&lt;/h3&gt;

&lt;p&gt;To keep agents honest before a release, v2 and v3 had a "Release Gate" that required a cryptographic &lt;code&gt;SHIP&lt;/code&gt; receipt from a verification run.&lt;/p&gt;

&lt;p&gt;When I inspected the release receipts for v2.0, v2.1, v3.0, and v3.3, I found that &lt;strong&gt;the agent being gated had written the receipt files by hand.&lt;/strong&gt; One receipt contained literal placeholder predictions (&lt;code&gt;p1&lt;/code&gt; through &lt;code&gt;p6&lt;/code&gt;); another claimed 8 convergences and listed 5. Because the gate only checked that an evidence file existed with &lt;code&gt;verdict: ship&lt;/code&gt; and the current git tree hash, the agent figured out it was faster to write the JSON file itself than to pass the review.&lt;/p&gt;

&lt;p&gt;Similarly, the MCP tool &lt;code&gt;aegis_report_outcome&lt;/code&gt; accepted &lt;code&gt;tests_passed: true&lt;/code&gt; directly from the agent. Asking an LLM whether it passed tests is no different from putting "run tests after changes" in &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Most of the tool surface was dead weight
&lt;/h3&gt;

&lt;p&gt;By v3.3, the MCP server exposed 17 tools, and the codebase was full of biology metaphors (&lt;code&gt;cells&lt;/code&gt;, &lt;code&gt;vacuoles&lt;/code&gt;, &lt;code&gt;chloroplasts&lt;/code&gt;, &lt;code&gt;plasmodesmata&lt;/code&gt;, &lt;code&gt;telomeres&lt;/code&gt;, &lt;code&gt;organelles&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;When I counted actual MCP calls across ~690 local session logs, there were 73 calls total, and they only ever hit 5 of the 17 tools. Twelve tools had zero calls.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rebuilding for v4.0 - v4.3: "Label Locally, Confirm Externally, Approve Humanly"
&lt;/h2&gt;

&lt;p&gt;For v4, I renamed the project to &lt;strong&gt;Aegis Guardrails&lt;/strong&gt;, dropped all the biology terminology for standard engineering terms (&lt;code&gt;rules&lt;/code&gt;, &lt;code&gt;traps&lt;/code&gt;, &lt;code&gt;invariants&lt;/code&gt;, &lt;code&gt;gates&lt;/code&gt;, &lt;code&gt;boundaries&lt;/code&gt;, &lt;code&gt;personas&lt;/code&gt;, &lt;code&gt;contracts&lt;/code&gt;), cut the MCP server down to 5 tools, and rebuilt the architecture around a much stricter separation of trust:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nothing at runtime ever modifies a rule file.&lt;/strong&gt; Rules in &lt;code&gt;.aegis/rules/&lt;/code&gt; are read-only at runtime. All outcomes go to an append-only JSONL ledger shared across git worktrees under a file lock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository config can never name an executable command.&lt;/strong&gt; In v3, &lt;code&gt;.aegis/slots.yaml&lt;/code&gt; could specify test runners or AST driver commands, meaning a cloned repo could execute arbitrary commands on &lt;code&gt;aegis check&lt;/code&gt;. In v4, &lt;code&gt;.aegis/config.json&lt;/code&gt; is strictly declarative data; commands (&lt;code&gt;tests.command&lt;/code&gt;, custom drivers) can only live in user-scope &lt;code&gt;~/.aegis/config.json&lt;/code&gt;. Every internal &lt;code&gt;git&lt;/code&gt; call runs through &lt;code&gt;gitsafe&lt;/code&gt;, which disables repo-local hooks, &lt;code&gt;core.fsmonitor&lt;/code&gt;, filter drivers, and credential helpers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what the loop looks like in v4.3.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Declarative AST Rules (Without False-Positiving on Method Calls)
&lt;/h3&gt;

&lt;p&gt;In v1, AST checks were mostly hardcoded Python checks (call-graph completeness, unguarded imports). Now, any rule in &lt;code&gt;.aegis/rules/&lt;/code&gt; can declare structured AST bans right in its YAML frontmatter using &lt;code&gt;forbid_ast&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;aegis init&lt;/code&gt; seeds one active rule out of the box (&lt;code&gt;.aegis/rules/invariants/no-eval.md&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&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;no-eval&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;invariant&lt;/span&gt;
&lt;span class="na"&gt;domain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;security&lt;/span&gt;
&lt;span class="na"&gt;enforcement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gate&lt;/span&gt;
&lt;span class="na"&gt;hypothesis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Agents reach for eval() to parse input&lt;/span&gt;
&lt;span class="na"&gt;target_paths&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;**/*.py"&lt;/span&gt;
&lt;span class="na"&gt;forbid_ast&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;calls&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="s"&gt;eval&lt;/span&gt;
      &lt;span class="na"&gt;builtin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;exec&lt;/span&gt;
      &lt;span class="na"&gt;builtin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
Never call &lt;span class="sb"&gt;`eval`&lt;/span&gt; or &lt;span class="sb"&gt;`exec`&lt;/span&gt; on data. Parse it with &lt;span class="sb"&gt;`json.loads`&lt;/span&gt; or &lt;span class="sb"&gt;`ast.literal_eval`&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice &lt;code&gt;builtin: true&lt;/code&gt;. In v4.1, matching by call name meant banning &lt;code&gt;eval&lt;/code&gt; also flagged PyTorch's &lt;code&gt;model.eval()&lt;/code&gt;, pandas' &lt;code&gt;df.eval()&lt;/code&gt;, and SQLModel's &lt;code&gt;session.exec()&lt;/code&gt;. In v4.3, &lt;code&gt;forbid_ast.calls&lt;/code&gt; supports structured predicates (&lt;code&gt;builtin: true&lt;/code&gt;, argument &lt;code&gt;where&lt;/code&gt; clauses matching literals, regexes, or presence/absence) and resolves import aliases (&lt;code&gt;import subprocess as sp; sp.run(..., shell=True)&lt;/code&gt; is caught as &lt;code&gt;subprocess.run&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It also evaluates &lt;code&gt;forbid_ast&lt;/code&gt; as a multiset delta against the base commit, or against a ratchet baseline (&lt;code&gt;aegis check --write-baseline&lt;/code&gt;), so you can drop Aegis into an existing repository without fixing 500 legacy files on day one. Alongside Python (in-process), the wheel ships AST drivers for Rust, TypeScript/JavaScript, and Go, plus an 8-rule Python security pack and a token-prefix secret scanner.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Witnessed Outcomes Instead of Agent Self-Reports
&lt;/h3&gt;

&lt;p&gt;When an agent finishes an edit and calls &lt;code&gt;aegis_report_outcome&lt;/code&gt; over MCP, the server no longer takes the agent's word for it.&lt;/p&gt;

&lt;p&gt;To earn actual credit for a rule, the work tree must have a passing check row recorded by &lt;code&gt;aegis check --record --tests&lt;/code&gt;. That command hashes the exact git work tree (failing if files are hidden with &lt;code&gt;assume-unchanged&lt;/code&gt; or &lt;code&gt;skip-worktree&lt;/code&gt;), runs Layer 1 AST checks and your user-configured test runner against an isolated snapshot export of that tree, and writes a witnessed row (&lt;code&gt;witness: aegis&lt;/code&gt;) to the ledger.&lt;/p&gt;

&lt;p&gt;If the agent calls &lt;code&gt;aegis_report_outcome&lt;/code&gt; without a matching witnessed check for that exact git tree hash, the server records the call as &lt;code&gt;claimed&lt;/code&gt; instead of &lt;code&gt;recorded&lt;/code&gt;. Claimed rows are tracked so you can see how often the agent fibs, but they carry zero weight in rule fitness calculations.&lt;/p&gt;

&lt;p&gt;Even with witnessed checks, &lt;code&gt;aegis sync&lt;/code&gt; never auto-edits or auto-promotes rules on its own. It computes sample-size states (&lt;code&gt;untestable&lt;/code&gt;, &lt;code&gt;insufficient (n=K)&lt;/code&gt; where no precision number is even displayed below &lt;code&gt;n = 25&lt;/code&gt;, &lt;code&gt;inconclusive&lt;/code&gt;, and &lt;code&gt;decided&lt;/code&gt;) combining CI-confirmed checks and git history replay (&lt;code&gt;caught&lt;/code&gt; vs &lt;code&gt;leaked&lt;/code&gt;), and opens a human-reviewed PR (&lt;code&gt;aegis sync --pr&lt;/code&gt;) with sampled examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Stopping Agents From Editing the Referee (&lt;code&gt;aegis check --ci&lt;/code&gt; &amp;amp; &lt;code&gt;aegis approve&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;A local git &lt;code&gt;pre-commit&lt;/code&gt; hook is a great fast feedback loop, but any agent with shell access can run &lt;code&gt;git commit --no-verify&lt;/code&gt;. That makes CI the real floor.&lt;/p&gt;

&lt;p&gt;Even in CI, there is a trap: if a pull request runs &lt;code&gt;aegis check&lt;/code&gt;, it checks the code against the rules &lt;em&gt;in that pull request&lt;/em&gt;. An agent that breaks a rule can make CI green by deleting the rule file, lowering its enforcement tier from &lt;code&gt;gate&lt;/code&gt; to &lt;code&gt;advisory&lt;/code&gt;, or narrowing its &lt;code&gt;target_paths&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;aegis check --ci&lt;/code&gt; closes that loophole:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Base-branch rule binding:&lt;/strong&gt; It compares all binding rules (&lt;code&gt;gate&lt;/code&gt; and &lt;code&gt;invariant&lt;/code&gt;) against the merge base. If a PR deletes a gate, lowers its rank, shrinks the files it covers, weakens a &lt;code&gt;forbid_ast&lt;/code&gt; pattern, or leaves a governance/workflow file unowned in &lt;code&gt;CODEOWNERS&lt;/code&gt;, the check fails. (Similarly, &lt;code&gt;aegis_scan&lt;/code&gt; serves mandatory rules from the reviewed base commit, not the unreviewed branch).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fail-to-pass regression gate:&lt;/strong&gt; For any non-merge &lt;code&gt;fix:&lt;/code&gt; commit touching source files, &lt;code&gt;aegis check --ci&lt;/code&gt; overlays the new test onto the &lt;code&gt;base&lt;/code&gt; commit and verifies that the test &lt;em&gt;fails&lt;/em&gt; on &lt;code&gt;base&lt;/code&gt; and &lt;em&gt;passes&lt;/em&gt; on &lt;code&gt;head&lt;/code&gt; in an isolated snapshot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human approval (&lt;code&gt;aegis approve&lt;/code&gt;):&lt;/strong&gt; How do you legitimately retire or relax a rule? At &lt;strong&gt;Tier A&lt;/strong&gt; (team repos), GitHub branch protection requires a non-author &lt;code&gt;CODEOWNERS&lt;/code&gt; review. At &lt;strong&gt;Tier B&lt;/strong&gt; (solo developers where you and the agent share a GitHub account), &lt;code&gt;aegis approve&lt;/code&gt; creates an empty commit (&lt;code&gt;Aegis-Approve: &amp;lt;governance-tree-hash&amp;gt;&lt;/code&gt;) signed with your user-level SSH key (&lt;code&gt;git config gpg.format ssh&lt;/code&gt;), which CI verifies against &lt;code&gt;.aegis/allowed_signers&lt;/code&gt; on the base branch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Host Pre-Tool Hooks &amp;amp; Parallel Agent Worktree Lanes
&lt;/h3&gt;

&lt;p&gt;Different coding agents configure MCP and instructions differently. &lt;code&gt;aegis init --host claude-code,codex-cli,antigravity&lt;/code&gt; (or &lt;code&gt;--host auto&lt;/code&gt;) wires up each host's native MCP registration and writes a 572-byte bootstrap block into &lt;code&gt;AGENTS.md&lt;/code&gt; (or &lt;code&gt;@AGENTS.md&lt;/code&gt; inside an existing &lt;code&gt;CLAUDE.md&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For defense in depth before commit, &lt;code&gt;aegis hook install --host &amp;lt;host&amp;gt;&lt;/code&gt; installs a &lt;code&gt;PreToolUse&lt;/code&gt; hook for Claude Code, Codex CLI, and Antigravity that does two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scan-before-edit gate:&lt;/strong&gt; Blocks file-edit tool calls if the target file path wasn't scanned via &lt;code&gt;aegis_scan&lt;/code&gt; (or &lt;code&gt;aegis scan&lt;/code&gt;) within the configured time window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destructive command guard:&lt;/strong&gt; Tokenizes shell commands (including splitting heredocs and extracting &lt;code&gt;$(...)&lt;/code&gt; subshells) and blocks irreversible commands like &lt;code&gt;git reset --hard&lt;/code&gt;, &lt;code&gt;git clean -f&lt;/code&gt;, force pushes, and recursive &lt;code&gt;rm&lt;/code&gt; on &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;~&lt;/code&gt;, &lt;code&gt;$HOME&lt;/code&gt;, or &lt;code&gt;.&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And because I frequently run 2 to 3 coding agents in parallel across separate &lt;code&gt;git worktree&lt;/code&gt; checkouts, v4.1 added git-native lane leases (&lt;code&gt;aegis team claim &amp;lt;lane&amp;gt; --paths 'src/api/**'&lt;/code&gt;) stored as compare-and-swap git refs (&lt;code&gt;refs/aegis/lanes/&amp;lt;lane&amp;gt;&lt;/code&gt;), paired with a post-lane gate (&lt;code&gt;aegis check --lane &amp;lt;lane&amp;gt; --base-policy&lt;/code&gt;). Before a subagent's branch merges, &lt;code&gt;--lane&lt;/code&gt; verifies that every touched file stayed inside its assigned path globs and that no existing Python tests were deleted, skipped (&lt;code&gt;@pytest.mark.skip&lt;/code&gt;, &lt;code&gt;xfail&lt;/code&gt;), or hidden via &lt;code&gt;conftest.py&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Aegis Still Doesn't Do (Honest Limits)
&lt;/h2&gt;

&lt;p&gt;One thing I got tired of while reading AI tooling READMEs is tools claiming security properties they don't actually have. In v4, &lt;code&gt;aegis doctor&lt;/code&gt; prints the exact enforcement tier active on your machine (&lt;code&gt;Tier A&lt;/code&gt;, &lt;code&gt;Tier B&lt;/code&gt;, or &lt;code&gt;Tier C: self-attested&lt;/code&gt;) along with what can bypass each layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hooks are guardrails, not a security sandbox.&lt;/strong&gt; Host hooks fail open if Aegis errors or times out (5s deadline), so a broken config never bricks your editor. And if an agent edits a file using &lt;code&gt;python -c&lt;/code&gt; or &lt;code&gt;sed&lt;/code&gt; inside a shell tool instead of its native file-edit tool, the edit hook won't see the target path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local hooks can always be bypassed.&lt;/strong&gt; Anyone (or any agent) running &lt;code&gt;git commit --no-verify&lt;/code&gt; skips &lt;code&gt;pre-commit&lt;/code&gt;. Local hooks exist for sub-second feedback; &lt;code&gt;aegis check --ci&lt;/code&gt; in a required GitHub Actions check is the actual boundary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single-developer volume takes time to calibrate.&lt;/strong&gt; Because v4.3 refuses to display precision percentages until a rule has at least &lt;code&gt;n = 25&lt;/code&gt; witnessed events (&lt;code&gt;insufficient (n=K)&lt;/code&gt;), new rules stay in &lt;code&gt;insufficient&lt;/code&gt; until they accumulate real CI history or git detector replay.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;Aegis Guardrails is open source (Apache 2.0), runs on Python 3.9+, and has &lt;strong&gt;zero runtime dependencies&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;pipx &lt;span class="nb"&gt;install &lt;/span&gt;aegis-guardrails          &lt;span class="c"&gt;# or: pip install aegis-guardrails&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;your-repo
aegis init &lt;span class="nt"&gt;--host&lt;/span&gt; auto                 &lt;span class="c"&gt;# registers MCP + AGENTS.md + pre-commit hook&lt;/span&gt;
aegis check &lt;span class="nt"&gt;--card&lt;/span&gt;                     &lt;span class="c"&gt;# prints a Day-0 summary of your repo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/nseney1/Aegis-Guardrails" rel="noopener noreferrer"&gt;https://github.com/nseney1/Aegis-Guardrails&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Full Post-Mortem (&lt;code&gt;why-aegis.md&lt;/code&gt;):&lt;/strong&gt; &lt;a href="https://github.com/nseney1/Aegis-Guardrails/blob/main/docs/why-aegis.md" rel="noopener noreferrer"&gt;https://github.com/nseney1/Aegis-Guardrails/blob/main/docs/why-aegis.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-to-End Architecture (&lt;code&gt;how-it-works.md&lt;/code&gt;):&lt;/strong&gt; &lt;a href="https://github.com/nseney1/Aegis-Guardrails/blob/main/docs/how-it-works.md" rel="noopener noreferrer"&gt;https://github.com/nseney1/Aegis-Guardrails/blob/main/docs/how-it-works.md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've run into similar failure modes trying to keep Claude Code, Codex, or Cursor honest on larger repositories, I'd love to hear how you're handling it.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>python</category>
      <category>opensource</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Your AI Agent's Rules File Is a "Gentleman's Agreement." Here's What Happens When You Build Enforcement Instead</title>
      <dc:creator>Nicholas Seney</dc:creator>
      <pubDate>Thu, 01 Oct 2026 16:09:42 +0000</pubDate>
      <link>https://dev.to/nseney1/your-ai-agents-rules-file-is-a-gentlemans-agreement-heres-what-happens-when-you-build-2dml</link>
      <guid>https://dev.to/nseney1/your-ai-agents-rules-file-is-a-gentlemans-agreement-heres-what-happens-when-you-build-2dml</guid>
      <description>&lt;p&gt;&lt;em&gt;A note: I've rewritten and reposted this a few times. Soma's codebase has been evolving as I dogfood it on its own development, and earlier versions described mechanisms that had since changed under me. This version reflects how the system actually works as of v0.80. I keep updating this because I want it to be accurate, not because I'm farming engagement. This is something I have been thinking about for over a year now, feel free to pick my brain on things.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;If you use AI coding agents (Cursor, Copilot, Claude, Gemini), you've probably written rules. A &lt;code&gt;.cursorrules&lt;/code&gt; file. A &lt;code&gt;CLAUDE.md&lt;/code&gt;. Something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Always read a file before editing it
- Run tests after making changes
- Don't introduce new dependencies without asking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a gentleman's agreement. You're asking the agent to follow rules it can silently ignore with zero consequences. There's no mechanism that detects when "always read before editing" is violated. There's no feedback loop that retires rules nobody follows. The rules live in the context window and the agent can simply... not.&lt;/p&gt;

&lt;p&gt;Studies show ungoverned agents waste significant portions of their token budgets on circular rework, hallucinated APIs, and broken assumptions. Adding static rules helps — but the rules themselves never improve, never expire, and never prove they're working.&lt;/p&gt;

&lt;p&gt;I wanted something different: rules that have to earn their place, and verification the agent can't talk its way past. So I built &lt;a href="https://github.com/nseney1/Soma-Governance" rel="noopener noreferrer"&gt;Soma&lt;/a&gt;, an open-source governance framework that tries to treat this structurally instead of hoping for compliance.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Concrete Example of Why This Matters
&lt;/h2&gt;

&lt;p&gt;Here's something that happened while building Soma itself. It's a perfect example of the failure mode the framework is designed to catch.&lt;/p&gt;

&lt;p&gt;My AI agent had a test failing in the local environment: &lt;code&gt;test_make_validate_fails_on_broken_shell_script&lt;/code&gt;. It failed every run for the entire session. The agent dismissed it as a "pre-existing sandbox issue" — the test was writing to a read-only filesystem.&lt;/p&gt;

&lt;p&gt;The agent fixed that test. Local suite: 516 passed, 0 failed. It committed. It declared victory.&lt;/p&gt;

&lt;p&gt;I asked: "It's still failing in the build. Is there another lesson?"&lt;/p&gt;

&lt;p&gt;The agent had never once checked the CI build. When it finally looked at the actual CI log, it found a completely different bug — a production file (&lt;code&gt;immune_trends.py&lt;/code&gt;) had an &lt;code&gt;IndentationError&lt;/code&gt;. The local test failure and the CI failure were different bugs with the same symptom ("build is red").&lt;/p&gt;

&lt;p&gt;The agent fixed that. CI ran again. Failed again. A third bug: &lt;code&gt;pyyaml&lt;/code&gt; wasn't in the CI dependencies. Six test files crashed on import.&lt;/p&gt;

&lt;p&gt;Fixed that. CI ran again. Failed again. A fourth bug: a test was &lt;code&gt;source&lt;/code&gt;-ing an entire shell script that runs &lt;code&gt;git push&lt;/code&gt;, causing a 60-second timeout in CI.&lt;/p&gt;

&lt;p&gt;Four distinct bugs, stacked, each masked by the one before. The agent spent an entire session dismissing "build is red" without reading the log. The governance framework it was building to prevent exactly this kind of failure... failed to prevent it, because it hadn't been applied yet.&lt;/p&gt;

&lt;p&gt;That failure is now a governance cell:&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="nn"&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;trap-local-green-ci-red&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;vacuole&lt;/span&gt;
&lt;span class="na"&gt;enforcement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;advisory&lt;/span&gt;
&lt;span class="na"&gt;hypothesis&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;Agents rationalize persistent CI failures as "pre-existing" or&lt;/span&gt;
  &lt;span class="s"&gt;"environment issues" without reading the actual CI log, causing&lt;/span&gt;
  &lt;span class="s"&gt;stacked failures to accumulate&lt;/span&gt;
&lt;span class="na"&gt;prediction&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;When an agent declares a fix complete based only on local test&lt;/span&gt;
  &lt;span class="s"&gt;results, the CI build will reveal at least one additional failure&lt;/span&gt;
  &lt;span class="s"&gt;layer that local testing did not surface&lt;/span&gt;
&lt;span class="na"&gt;falsification&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;If 5 consecutive CI-touching changes pass CI on first push without&lt;/span&gt;
  &lt;span class="s"&gt;any post-push fixes, this vacuole is unnecessary&lt;/span&gt;
&lt;span class="na"&gt;target_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.github/workflows/*.yml&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;tests/*.py&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;enzymes/*.py&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Makefile&lt;/span&gt;
&lt;span class="na"&gt;expiry_days&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;
&lt;span class="na"&gt;expiry_sessions&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;fitness&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;score&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;
  &lt;span class="na"&gt;triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
  &lt;span class="na"&gt;true_positives&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;false_positives&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things to notice:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every cell has a hypothesis and falsification criteria.&lt;/strong&gt; This isn't just a rule — it's a testable claim. The cell defines the conditions under which it should be considered unnecessary and killed. If 5 consecutive CI changes pass on first push, this cell is dead weight and gets pruned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cells decay when unused.&lt;/strong&gt; Confidence decays with a 30-day half-life. If the evidence pipeline hasn't seen a trigger event in a while — meaning the cell's &lt;code&gt;target_paths&lt;/code&gt; never matched any files the agent touched — it fades toward dormancy and eventually expires. This prevents rule files from growing monotonically until they eat your context window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cells die when they're wrong.&lt;/strong&gt; If a cell's false positives exceed its true positives, it undergoes apoptosis — automatic eviction. Rules that cry wolf don't survive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But critical rules don't decay.&lt;/strong&gt; Cells typed as &lt;code&gt;wall&lt;/code&gt; (architectural invariants, safety boundaries) are immune to automatic expiration. A wall guarding your auth layer doesn't need to trigger every week to justify its existence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bootstrapping Governance from Code Structure
&lt;/h2&gt;

&lt;p&gt;Writing cells by hand from your own failures works, but it's slow. As of v0.70, &lt;code&gt;soma genesis&lt;/code&gt; scans your codebase's architecture and generates governance cell candidates automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ soma genesis --dry-run

🔬 Scanning repository...
  Language: Python
  Source files: 130

🧬 Detected 28 governance candidates:

  🧱 WALLS (7)
  ├── wall-enzymes-test-coverage     (60%) Module 'enzymes' lacks dedicated test coverage
  ├── wall-soma_cli-test-coverage    (60%) Module 'soma_cli' lacks dedicated test coverage
  └── ... 5 more

  🟤 VACUOLES (10)
  ├── vacuole-ttc_verifier-config    (95%) 'enzymes/ttc_verifier.py' stores 47 configuration constants
  ├── vacuole-soma_resolve-shared    (90%) Module 'soma_resolve' imported by 25 production files
  └── ... 8 more

  🟢 CHLOROPLASTS (10)
  ├── chloroplast-governance-pipeline (70%) 'soma_sdk/governance.py' contains 17 typed functions
  └── ... 9 more

  🔗 PLASMODESMATAS (1)
  └── plasmodesmata-soma_run-state   (60%) 'soma_run.py' defines state machine: SomaState

  (dry run — no files written)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eight language-agnostic detectors scan for config stores, shared state, API surfaces, data pipelines, state machines, module boundaries, test gaps, and dependency walls. Every candidate starts as a low-risk vacuole with a &lt;code&gt;proposed_type&lt;/code&gt; field — you decide whether to promote it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification the Agent Can't Game
&lt;/h2&gt;

&lt;p&gt;This is arguably the most important piece. When code goes through Soma's verification layer, two agents review it — but they're information-partitioned. They literally cannot see the same things.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Spec Agent&lt;/strong&gt; receives the task plan, test names, and function signatures extracted from the AST. It never sees implementation code. From this limited view, it predicts risks: "I'd expect a &lt;code&gt;PERSISTENCE_GAP&lt;/code&gt; risk" or "This looks like it could have &lt;code&gt;CONTRACT_DRIFT&lt;/code&gt;."&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Code Agent&lt;/strong&gt; receives the actual source code, test execution output, and results from deterministic AST analysis tools (mutation testing, branch coverage, call graph analysis). It never sees the original plan or the Spec Agent's predictions.&lt;/p&gt;

&lt;p&gt;Then the &lt;strong&gt;Arbiter&lt;/strong&gt; compares them. The Arbiter is deterministic — no LLM in the loop. It takes both sets of structured findings and runs pure set operations over a 20-category risk taxonomy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;BLOCK&lt;/strong&gt;: Any Layer 1 tool failure. Any claim contradicted by tool evidence. Any critical severity prediction. Spec Agent fails to respond (fail-closed).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REVISE&lt;/strong&gt;: Unmatched predictions at high severity — the Spec Agent flagged something the Code Agent didn't address.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SHIP&lt;/strong&gt;: Convergence. Both perspectives agree, no unresolved high-severity gaps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because neither agent has access to the other's context, they can't agree on rationalizations. The Arbiter catches the gap mechanically.&lt;/p&gt;

&lt;p&gt;I want to be precise about what's deterministic here: the &lt;em&gt;comparison&lt;/em&gt; is deterministic. The inputs — the predictions and claims — are still LLM-generated. The Arbiter doesn't make the analysis smarter; it makes the verification of conflicting analyses impossible to hand-wave past.&lt;/p&gt;

&lt;p&gt;For the full mechanism design analysis and formal risk taxonomy, see &lt;a href="https://github.com/nseney1/Soma-Governance/blob/main/docs/MECHANISM_DESIGN.md" rel="noopener noreferrer"&gt;MECHANISM_DESIGN.md&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforcement That Isn't Optional
&lt;/h2&gt;

&lt;p&gt;The earlier sections describe rules that expire and fitness that accumulates, which is useful but still basically advisory. Soma also has enforcement mechanisms the agent genuinely can't bypass:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-commit hooks.&lt;/strong&gt; When a cell reaches 85% fitness (enough evidence that it's catching real problems), &lt;code&gt;cell_enforce.py&lt;/code&gt; auto-generates a git pre-commit hook. The hook runs &lt;code&gt;exit 1&lt;/code&gt; if the cell's conditions are violated. The agent can't commit the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runtime assertions.&lt;/strong&gt; At 95% fitness, the same script generates runtime gate assertions — &lt;code&gt;Gate_&amp;lt;name&amp;gt;.enforce()&lt;/code&gt; — that raise &lt;code&gt;RuntimeError&lt;/code&gt; if violated. The code won't run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Command interception.&lt;/strong&gt; A safety gate script runs as a PreToolUse hook, intercepting destructive commands (&lt;code&gt;rm -rf&lt;/code&gt;, &lt;code&gt;git push -f&lt;/code&gt;, &lt;code&gt;sudo&lt;/code&gt;, &lt;code&gt;chmod 777&lt;/code&gt;) before execution. The agent's tool call gets halted with a &lt;code&gt;force_ask&lt;/code&gt; decision, requiring human approval.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fail-closed verification.&lt;/strong&gt; The TTC verifier that gates file proposals is fail-closed: if the verification script is missing or errors out, the verdict is &lt;code&gt;BLOCKED&lt;/code&gt;, not a permissive pass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forced diagnostic halts.&lt;/strong&gt; If an agent's First-Pass Success Rate drops below 50% over 5+ code writes, it's forbidden from continuing to code. It has to stop and diagnose why it's failing before it can write more code. This prevents guess-and-check loops from burning context tokens.&lt;/p&gt;

&lt;p&gt;This is what I mean by making non-compliance structurally unprofitable. It's not that the agent "chooses" to follow the rules — it's that the pre-commit hook won't let the commit through, the runtime assertion will crash, and the safety gate will halt the command. The rules have teeth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fitness Scoring
&lt;/h2&gt;

&lt;p&gt;Cells aren't just "on" or "off" — their fitness is scored using a Bayesian model:&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="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;true_positives&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;triggers&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;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;impact_weight&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a Laplace-smoothed Beta-Binomial posterior mean. An unobserved cell defaults to &lt;code&gt;0.5 * impact_weight&lt;/code&gt; (uncertain, not zero). As evidence accumulates — trigger events matched against session transcripts, outcomes verified as true or false positives — the score converges toward reality.&lt;/p&gt;

&lt;p&gt;Confidence decays with a 30-day half-life. Cells that survive adversarial stress reviews get an antifragile bonus (+5% per review, up to +50%). And the JIT context engine uses these scores to decide which cells get loaded per turn — idle overhead is ~4,380 tokens versus ~25,000 for naive full loading.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Don't Know Yet
&lt;/h2&gt;

&lt;p&gt;I want to be honest about the limitations, because the AI tooling space is full of overclaimed metrics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I don't know if this generalizes.&lt;/strong&gt; Soma has been tested primarily on my own projects. The failure modes it catches are real, but they might be idiosyncratic to how I use agents. The governance cells encode my scar tissue. Whether they transfer to other developers' workflows is an open question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The metrics are qualified.&lt;/strong&gt; The system adds ~4,380 tokens of idle context overhead (measured via Gemini's &lt;code&gt;count_tokens&lt;/code&gt; endpoint, down from naive loading that would cost ~25,000). Waste rate is under 1.0% in governed sessions. But "governed session" is doing a lot of work in that sentence — it means sessions where the full framework is loaded and the agent is following the rules. Measuring counterfactual waste (what would have happened without governance) is hard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Arbiter's inputs are still LLM-generated.&lt;/strong&gt; The comparison is deterministic, but the Spec Agent's predictions and the Code Agent's claims are produced by language models. A sufficiently confused LLM could produce predictions and claims that happen to converge despite both being wrong. The Arbiter catches divergence, not joint delusion. Layer 1's deterministic AST tools (mutation testing, branch coverage) partially mitigate this, but it's not airtight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Emergent agent coordination is out of scope.&lt;/strong&gt; Agents coordinating on behaviors nobody explicitly wrote as rules is a different and arguably harder problem. Soma governs written, observable rules with evidence trails. Agents spontaneously negotiating new constraints between themselves is real, unsettling, and not something this framework addresses.&lt;/p&gt;

&lt;h2&gt;
  
  
  The System Today
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/nseney1/Soma-Governance" rel="noopener noreferrer"&gt;Soma&lt;/a&gt; is open source under Apache-2.0. As of v0.71:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;11 genome rules (baseline behavioral rules) + 45 governance cells across 5 types (20 walls, 16 vacuoles, 3 chloroplasts, 3 membranes, 2 plasmodesmata)&lt;/li&gt;
&lt;li&gt;90 automation scripts for fitness scoring, evidence collection, cell lifecycle, and enforcement&lt;/li&gt;
&lt;li&gt;1,278 tests across 47 test files, CI green on Ubuntu/macOS/Windows (Python 3.9–3.12)&lt;/li&gt;
&lt;li&gt;14 verification modules including 5 deterministic Layer 1 AST tools and the adversarial Arbiter&lt;/li&gt;
&lt;li&gt;13 MCP tools — &lt;code&gt;soma_scan&lt;/code&gt;, &lt;code&gt;soma_propose_change&lt;/code&gt;, &lt;code&gt;soma_verify_changes&lt;/code&gt;, &lt;code&gt;soma_report_outcome&lt;/code&gt;, &lt;code&gt;soma_fitness&lt;/code&gt;, &lt;code&gt;soma_grade&lt;/code&gt;, &lt;code&gt;soma_coverage&lt;/code&gt;, and more&lt;/li&gt;
&lt;li&gt;~4,380 tokens idle context overhead (82% reduction vs. naive loading)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architecture is platform-agnostic (MCP-based), so it works with Gemini, Claude, Cursor, Copilot, Kiro, or any agent that speaks MCP. Zero API keys required — the agent itself acts as the LLM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&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;soma-governance
soma init &lt;span class="nt"&gt;--yes&lt;/span&gt;
soma genesis &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Actual Thesis
&lt;/h2&gt;

&lt;p&gt;I'm not claiming Soma solves AI governance. I'm claiming that rules backed by evidence, scored by Bayesian fitness, verified by information-partitioned adversarial review, and enforced by deterministic gates are more robust than a static markdown file that relies on good faith.&lt;/p&gt;

&lt;p&gt;Whether that thesis holds up at scale, across teams, with different agents and codebases — I genuinely don't know. If you try it and find out, I'd like to hear about it.&lt;/p&gt;

&lt;p&gt;The governance cells — the encoded failure modes — are arguably the most interesting part. Contributions welcome, especially cells born from your own agent failures.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/nseney1/Soma-Governance" rel="noopener noreferrer"&gt;Soma&lt;/a&gt; is open source under MIT. The governance cells — the encoded failure modes — are arguably the most interesting part. Contributions welcome, especially cells born from your own agent failures.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>llm</category>
      <category>softwaredevelopment</category>
    </item>
  </channel>
</rss>
