<?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: Hrutav Modha</title>
    <description>The latest articles on DEV Community by Hrutav Modha (@hrutav_modha_c0c028285f7e).</description>
    <link>https://dev.to/hrutav_modha_c0c028285f7e</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3840520%2Fcd7dc7fd-35c4-48e2-8945-c37082ccaf60.jpg</url>
      <title>DEV Community: Hrutav Modha</title>
      <link>https://dev.to/hrutav_modha_c0c028285f7e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hrutav_modha_c0c028285f7e"/>
    <language>en</language>
    <item>
      <title>I'm a Diploma Student. I Built an AI Agent Sandbox in 2–3 Days Using setfacl</title>
      <dc:creator>Hrutav Modha</dc:creator>
      <pubDate>Mon, 23 Mar 2026 17:31:54 +0000</pubDate>
      <link>https://dev.to/hrutav_modha_c0c028285f7e/the-problem-nobody-is-solving-properly-in-multi-agent-ai-43d0</link>
      <guid>https://dev.to/hrutav_modha_c0c028285f7e/the-problem-nobody-is-solving-properly-in-multi-agent-ai-43d0</guid>
      <description>&lt;p&gt;I'm in 4th semester Diploma in Computer Engineering.&lt;/p&gt;

&lt;p&gt;I don't know AutoGen, CrewAI, or Docker.&lt;/p&gt;

&lt;p&gt;I had a problem, sat at my PC, and solved it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;I was running agentic workflows via Gemini CLI using a markdown task file.&lt;/p&gt;

&lt;p&gt;Wanted a loop: Developer → Tester → Reviewer.&lt;/p&gt;

&lt;p&gt;Issue: &lt;strong&gt;Tester could read implementation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So instead of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"Does this satisfy the spec?"&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It asked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"Does this match the code?"&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's not testing — it's validation bias. I saw it happen: wrong code passed &lt;br&gt;
because tests were influenced by source.&lt;/p&gt;

&lt;p&gt;"Tell AI not to read files" is not a security model. It's trust.&lt;/p&gt;

&lt;p&gt;I needed enforcement.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Idea
&lt;/h2&gt;

&lt;p&gt;Linux already solves this: &lt;strong&gt;filesystem-level access control.&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;useradd &lt;span class="nt"&gt;--system&lt;/span&gt; &lt;span class="nt"&gt;--no-create-home&lt;/span&gt; &lt;span class="nt"&gt;--shell&lt;/span&gt; /usr/sbin/nologin kernelcage-agent
setfacl &lt;span class="nt"&gt;-m&lt;/span&gt; u:kernelcage-agent:--- tests/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If Tester physically cannot read &lt;code&gt;src/&lt;/code&gt;, the problem is eliminated at the &lt;br&gt;
OS level. No prompts. No containers. Just the kernel refusing the syscall.&lt;/p&gt;

&lt;p&gt;The key insight: &lt;code&gt;setfacl&lt;/code&gt; lets you set permissions per user without &lt;br&gt;
touching anyone else's access. My own permissions stay untouched. Only &lt;br&gt;
&lt;code&gt;kernelcage-agent&lt;/code&gt; gets restricted.&lt;/p&gt;


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

&lt;p&gt;3 agents, enforced by kernel.&lt;/p&gt;

&lt;p&gt;No need for 3 users. Agents run sequentially — use one unprivileged &lt;br&gt;
daemon user (&lt;code&gt;kernelcage-agent&lt;/code&gt;), flip ACL permissions per turn using &lt;br&gt;
&lt;code&gt;setfacl&lt;/code&gt; before handing control to each agent.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;TASKS.md&lt;/th&gt;
&lt;th&gt;REVIEW.md&lt;/th&gt;
&lt;th&gt;src/&lt;/th&gt;
&lt;th&gt;tests/&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Developer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;R+W&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tester&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;R+W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reviewer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;R+W&lt;/td&gt;
&lt;td&gt;R+W&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Developer cannot read &lt;code&gt;tests/&lt;/code&gt; — kernel refuses the call&lt;/li&gt;
&lt;li&gt;Tester cannot read &lt;code&gt;src/&lt;/code&gt; — derives tests only from spec, not implementation&lt;/li&gt;
&lt;li&gt;Reviewer sees all, modifies only coordination files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; kernelcage-agent bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;generated_command&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No sudo, no password — privilege escalation fails instantly at OS level.&lt;/p&gt;

&lt;p&gt;The permission flip in Python looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mark_no_access&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;setfacl -R -m u:kernelcage-agent:--- &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;setfacl -R -d -m u:kernelcage-agent:--- &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mark_write_access&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;setfacl -R -m u:kernelcage-agent:rwx &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;setfacl -R -d -m u:kernelcage-agent:rwx &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mark_read_only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;setfacl -R -m u:kernelcage-agent:rx &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;setfacl -R -d -m u:kernelcage-agent:rx &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-d&lt;/code&gt; flag sets default ACLs so newly created files inside a directory &lt;br&gt;
automatically inherit the same restrictions. Without it, a file created by &lt;br&gt;
the Developer agent would have no ACL and be readable by everyone.&lt;/p&gt;


&lt;h2&gt;
  
  
  Protocol
&lt;/h2&gt;

&lt;p&gt;Two markdown files. That's the entire inter-agent communication layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;TASKS.md&lt;/code&gt;&lt;/strong&gt; — forward progress&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="p"&gt;-&lt;/span&gt; [ ] Task 1
&lt;span class="p"&gt;-&lt;/span&gt; [x] Task 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;REVIEW.md&lt;/code&gt;&lt;/strong&gt; — bug channel&lt;/p&gt;

&lt;p&gt;When this file exists, it overrides normal flow across all three agents.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Present → fix described bug first&lt;/li&gt;
&lt;li&gt;Absent → continue with next task&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No APIs. No message queues. Files are the protocol.&lt;/p&gt;




&lt;h2&gt;
  
  
  Feedback Loop
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TASKS.md → Developer → src/
           (no test access)
                ↓
           Tester → tests/
           (no src access)
                ↓
           Reviewer → runs suite
                ↓
          FAIL        PASS
           ↓            ↓
      append          mark done
      REVIEW.md       commit + push
           ↓
      Developer
      reads bug,
      fixes src/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No human intervention in the normal path.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prior Art Search
&lt;/h2&gt;

&lt;p&gt;Searched GitHub, ArXiv, Google Scholar, HackerNews, Reddit, and &lt;br&gt;
documentation of every major agentic framework.&lt;/p&gt;

&lt;p&gt;Findings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All frameworks use either prompt isolation or containers&lt;/li&gt;
&lt;li&gt;None applied native Linux filesystem permissions to isolate agents 
from each other in a coding loop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Closest match: A March 2026 academic paper on a hospital agent OS using &lt;br&gt;
the exact same mechanism — Linux user isolation, ACL-based file permissions, &lt;br&gt;
inter-agent coordination via document writes — for medical agents under &lt;br&gt;
HIPAA compliance requirements.&lt;/p&gt;

&lt;p&gt;Same architecture. Different domain. Published after this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Current Status
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Single Python script&lt;/li&gt;
&lt;li&gt;Uses a predefined &lt;code&gt;TASKS.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;One unprivileged daemon user&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setfacl&lt;/code&gt; permission flipping per agent turn&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No config system, no multi-provider support, no packaging yet.&lt;/p&gt;

&lt;p&gt;Works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/hrutavmodha/ai-sandboxer" rel="noopener noreferrer"&gt;https://github.com/hrutavmodha/ai-sandboxer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note: &lt;code&gt;setfacl&lt;/code&gt; requires ACL support enabled on your filesystem.&lt;br&gt;
Check with &lt;code&gt;mount | grep acl&lt;/code&gt;. If not enabled:&lt;br&gt;
&lt;code&gt;sudo mount -o remount,acl /&lt;/code&gt;)&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Honest Note
&lt;/h2&gt;

&lt;p&gt;Built in 2-3 days.&lt;/p&gt;

&lt;p&gt;No prior framework knowledge. No Docker. No awareness of what the &lt;br&gt;
"standard" solution was supposed to be.&lt;/p&gt;

&lt;p&gt;Just looked at the problem and reached for what the OS already provides.&lt;/p&gt;

&lt;p&gt;Sometimes not knowing the established approach means you find a &lt;br&gt;
different one.&lt;/p&gt;

&lt;p&gt;If there's a flaw, I genuinely want to know.&lt;/p&gt;

&lt;p&gt;Stars, issues, and brutal feedback all welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>linux</category>
      <category>security</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
