<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:blog="https://jonesrussell.github.io/blog/ns"><channel><title>Sovereignty on Web Developer Blog</title><link>https://jonesrussell.github.io/blog/tags/sovereignty/</link><description>Recent content in Sovereignty on Web Developer Blog</description><image><title>Web Developer Blog</title><url>https://jonesrussell.github.io/blog/images/og-default.png</url><link>https://jonesrussell.github.io/blog/images/og-default.png</link></image><generator>Hugo -- 0.163.3</generator><language>en-us</language><lastBuildDate>Thu, 02 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://jonesrussell.github.io/blog/tags/sovereignty/feed.xml" rel="self" type="application/rss+xml"/><item><title>Bimaaji: agent-safe mutations for Waaseyaa</title><link>https://jonesrussell.github.io/blog/bimaaji-agent-safe-mutations/</link><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><guid>https://jonesrussell.github.io/blog/bimaaji-agent-safe-mutations/</guid><category>ai</category><blog:tag>waaseyaa</blog:tag><blog:tag>ai-agents</blog:tag><blog:tag>php</blog:tag><blog:tag>sovereignty</blog:tag><description>Why AI agents modifying a Waaseyaa app need a DSL, an AST-safe patch generator, and sovereignty guardrails, instead of raw file edits.</description><content:encoded><![CDATA[<p>Ahnii!</p>
<p>If you let an AI agent modify your application, the agent needs more than a text editor. Raw <code>str_replace</code> on a PHP file passes a lot of tests and still breaks things an hour later in production, because the tool has no idea what the file actually represents. Bimaaji is the <a href="https://github.com/waaseyaa/framework">Waaseyaa</a> package that gives agents a structured path from &ldquo;I want to add a field to this entity&rdquo; to a reviewable patch that a community&rsquo;s sovereignty rules have already vetted. This post walks through what shipped in <code>waaseyaa/bimaaji</code> and why each piece exists.</p>
<blockquote>
<p><strong>Prerequisites:</strong> familiarity with Waaseyaa&rsquo;s package layout, PHP 8.4+, and the idea that an application has more state than the filesystem (routes, entities, introspection metadata).</p>
</blockquote>
<h2 id="why-not-just-let-the-agent-edit-files">Why not just let the agent edit files</h2>
<p>The failure mode you want to avoid: an agent reads a prompt like &ldquo;add a <code>published_at</code> field to the <code>Post</code> entity,&rdquo; does a reasonable-looking edit to <code>Post.php</code>, and leaves the rest of the app inconsistent. The migration is missing. The JSON:API resource doesn&rsquo;t expose the field. The admin panel still doesn&rsquo;t know it exists. The sovereignty profile that was supposed to block the change on a local-only deployment never got consulted.</p>
<p>Each of those is a different subsystem. A good agent can write a correct edit to any one of them. What a filesystem-level tool cannot do is ensure the edit is <em>coordinated</em> across all of them and is <em>allowed</em> under the community&rsquo;s posture.</p>
<p>Bimaaji separates that problem into three stages: introspect, propose, patch.</p>
<h2 id="the-pipeline">The pipeline</h2>
<p>The package description (from <code>packages/bimaaji/composer.json</code>) spells it out: <em>application graph introspection and agent-safe mutation for Waaseyaa.</em> The flow is:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-fallback" data-lang="fallback"><span style="display:flex;"><span>Introspection → ApplicationGraph → MutationRequest → Validator → PatchGenerator → PatchSet
</span></span></code></pre></div><p>An agent reads the graph, submits a structured mutation request, a validator checks it against sovereignty rules, and the patch generator returns reviewable diffs. Nothing touches the filesystem until a human (or a higher-level workflow) accepts the <code>PatchSet</code>.</p>
<h2 id="introspection-what-the-agent-reads-first">Introspection: what the agent reads first</h2>
<p><code>src/Introspection/</code> holds a provider for every surface the agent might need context on:</p>
<ul>
<li><code>AdminIntrospectionProvider</code> — what&rsquo;s exposed to the admin panel</li>
<li><code>EntityIntrospectionProvider</code> — entity definitions</li>
<li><code>JsonApiIntrospectionProvider</code> — public API shape</li>
<li><code>PublicSurfaceProvider</code> — what&rsquo;s reachable from outside</li>
<li><code>RoutingIntrospectionProvider</code> — route table</li>
<li><code>SovereigntyIntrospectionProvider</code> — the community&rsquo;s deployment posture and rules</li>
</ul>
<p>Each one implements <code>GraphSectionProviderInterface</code> and contributes a <code>GraphSection</code> to the <code>ApplicationGraph</code>. The point is that the agent never reads source files to understand the app. It reads the graph. That is the canonical view.</p>
<p>This matters because it means an agent&rsquo;s understanding of your app is a data structure you control, not whatever the agent&rsquo;s context window happened to pick up from grep.</p>
<h2 id="the-task-dsl">The task DSL</h2>
<p><code>src/Dsl/</code> is the entry point for agents. <code>TaskParser</code> parses a structured task definition into <code>TaskDefinition</code> objects. <code>TaskPipeline</code> runs them, producing a <code>TaskPipelineResult</code>. The DSL describes <em>what</em> to change (add a field, add an entity type, add a route stub, add a test skeleton), not <em>how</em>.</p>
<p>That separation is the whole point. An agent says &ldquo;add field <code>published_at: datetime</code> to entity <code>Post</code>.&rdquo; Bimaaji decides how that compiles into a PHP edit, a migration stub, an admin surface update, and a JSON:API resource change. The agent is not writing PHP. It&rsquo;s writing a task.</p>
<h2 id="mutation-the-reviewable-proposal">Mutation: the reviewable proposal</h2>
<p><code>src/Mutation/</code> turns a parsed task into a <code>MutationRequest</code>, runs it through <code>MutationValidator</code>, and returns a <code>MutationResult</code>. The validator is where the sovereignty guardrails plug in.</p>
<p><code>src/Policy/SovereigntyGuardrails.php</code> and <code>GuardrailRule</code> hold the rules. The model: a community declares a <code>SovereigntyProfile</code> (local, hybrid, cloud) on their Waaseyaa deployment. Certain mutations are allowed under certain profiles and not others. A local-only community might forbid any mutation that adds outbound network dependencies. A cloud-hosted community might allow them but require a specific audit annotation. The guardrails are declarative, matrixed per profile, and they <em>stop the mutation at the proposal stage</em>, not after the patch has already rewritten files.</p>
<p>This is where Waaseyaa&rsquo;s sovereignty story gets teeth. Community control over AI-driven changes is not a policy document. It&rsquo;s a validator in the mutation path.</p>
<h2 id="patching-ast-not-strings">Patching: AST, not strings</h2>
<p><code>src/Patch/PatchGenerator.php</code> takes a validated <code>MutationRequest</code> and produces a <code>PatchSet</code> of <code>PatchEntry</code> objects. For PHP files, it uses <a href="https://github.com/nikic/PHP-Parser">nikic/php-parser</a> via <code>PhpFileBuilder</code> to round-trip through an AST. That means the patch is syntactically valid by construction. You cannot generate a patch that breaks parsing because the patch itself is a parsed tree that gets printed back out.</p>
<p>For non-PHP files, the generator falls back to constrained operations with risk flags. Anything that can&rsquo;t be AST-verified is surfaced as unsafe and requires an explicit opt-in. That&rsquo;s the right default. Agents should fail loudly on anything they can&rsquo;t guarantee.</p>
<h2 id="the-integration-test">The integration test</h2>
<p><code>tests/Integration/FullPipelineTest.php</code> runs the whole flow: introspect an app, submit a task through the DSL, validate against guardrails, generate a patch, assert the patch is well-formed. It&rsquo;s the check that all five subsystems (Graph, Dsl, Mutation, Policy, Patch) still agree on the contracts between them. When any one of them changes, that test catches the drift.</p>
<h2 id="where-this-fits-in-the-bigger-picture">Where this fits in the bigger picture</h2>
<p>Bimaaji is the seam where Waaseyaa&rsquo;s AI tooling meets Waaseyaa&rsquo;s community governance. The whole Waaseyaa thesis is that the software communities run should answer to the community, not the other way around. Sovereignty profiles are the policy expression of that. Bimaaji is the enforcement point for anything an AI agent wants to do to the app.</p>
<p>The package is at <a href="https://github.com/waaseyaa/framework/tree/main/packages/bimaaji">waaseyaa/framework packages/bimaaji</a>. The README is still a scaffold note; the code has moved past that. If you want to read one thing, start with <code>tests/Integration/FullPipelineTest.php</code> — it&rsquo;s the shortest honest tour of what the pipeline does end to end.</p>
<p>Baamaapii</p>
]]></content:encoded></item></channel></rss>