<?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: Kapil Ratnani</title>
    <description>The latest articles on DEV Community by Kapil Ratnani (@kapilratnani).</description>
    <link>https://dev.to/kapilratnani</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%2F514800%2F89f989f5-4140-4447-82ff-35b8639f0b79.jpeg</url>
      <title>DEV Community: Kapil Ratnani</title>
      <link>https://dev.to/kapilratnani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kapilratnani"/>
    <language>en</language>
    <item>
      <title>aienv - Sandbox any agent</title>
      <dc:creator>Kapil Ratnani</dc:creator>
      <pubDate>Sat, 18 Jul 2026 11:36:41 +0000</pubDate>
      <link>https://dev.to/kapilratnani/aienv-sandbox-any-agent-17hp</link>
      <guid>https://dev.to/kapilratnani/aienv-sandbox-any-agent-17hp</guid>
      <description>&lt;p&gt;AI coding agents are amazing — until they &lt;code&gt;rm -rf&lt;/code&gt; something, leak an API key, or leave your project in a broken state.&lt;/p&gt;

&lt;p&gt;Every project needs different tools, credentials, and configs. Yet most of us run agents directly on our host, giving them unrestricted filesystem access, unfiltered network calls, and no audit trail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;aienv&lt;/strong&gt; fixes that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kapilratnani/aienv" rel="noopener noreferrer"&gt;github.com/kapilratnani/aienv&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo9n5mep09gc3keyo0a6m.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo9n5mep09gc3keyo0a6m.jpg" alt=" " width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One YAML file defines everything your agent needs: the binary to run, which files to mount, what APIs it can talk to, and which environment variables to inject. aienv builds a Docker image from that YAML, launches a sandboxed container, runs an HTTP proxy for network enforcement, and writes every network request to a JSONL audit log.&lt;/p&gt;

&lt;p&gt;Agents are treated as &lt;strong&gt;black boxes&lt;/strong&gt; — aienv doesn't care whether you run Claude Code, OpenCode, Cursor, Pi, or a custom script. If it runs on a CLI, it works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/kapilratnani/aienv@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create an environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aienv create my-coding-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This walks you through an interactive setup. The result is a YAML file at &lt;code&gt;~/.local/share/aienv/my-coding-env/env.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;env&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;my-coding-env&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coding env for my project&lt;/span&gt;

&lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm install -g opencode-ai&lt;/span&gt;
  &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;opencode&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;env:GITHUB_TOKEN"&lt;/span&gt;
  &lt;span class="na"&gt;mounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/path/to/your/project&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/workspace&lt;/span&gt;
      &lt;span class="na"&gt;writable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch the sandbox:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aienv up my-coding-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your agent runs inside an isolated Docker container. Your host filesystem is untouched. When you exit, the container is removed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mount Agent Configs &amp;amp; Skills
&lt;/h2&gt;

&lt;p&gt;Agents need their configs, context files, and skill directories. Mount them as read-only by default — only make writable what the agent must modify.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/projects/my-app&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/workspace&lt;/span&gt;
      &lt;span class="na"&gt;writable&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;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.claude&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.claude&lt;/span&gt;
      &lt;span class="na"&gt;writable&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;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.agents/skills/caveman&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.agents/skills/caveman&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.agents/skills/agent-browser&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.agents/skills/agent-browser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All mounts are &lt;strong&gt;read-only&lt;/strong&gt; by default. The &lt;code&gt;writable: true&lt;/code&gt; flag is explicit — you opt into it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4uljmdkge67o7yodreco.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4uljmdkge67o7yodreco.jpg" alt=" " width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Environment Variables
&lt;/h2&gt;

&lt;p&gt;Pass secrets through environment variables from the host — never baked into images:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;env:ANTHROPIC_API_KEY"&lt;/span&gt;
    &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;env:GITHUB_TOKEN"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;env:&lt;/code&gt; prefix tells aienv to passthrough the value from your host environment at runtime. The image stays portable and hash-cached.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;p&gt;Need system packages or custom installs? Declare them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;deps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;nodejs&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;git&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;curl&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;golang-go&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;ripgrep&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;go install github.com/foo/bar@latest&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo install some-tool&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;aienv installs these at build time. The image is cached by the SHA-256 hash of your entire YAML — change anything, and the image auto-rebuilds on next activation.&lt;/p&gt;




&lt;h2&gt;
  
  
  One-Shot Mode — Tell the Agent What to Do and Walk Away
&lt;/h2&gt;

&lt;p&gt;This is where aienv shines.&lt;/p&gt;

&lt;p&gt;Instead of dropping into an interactive session, you can &lt;strong&gt;send a prompt directly&lt;/strong&gt; and let the agent work independently. The agent does its job, commits changes, creates a PR, and exits. The container self-destructs. You get a clean audit log.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aienv up claude-dev &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Refactor the auth module to use JWT and create the PR using gh cli"&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-p&lt;/code&gt; flag sends the prompt. The &lt;code&gt;-x&lt;/code&gt; flag means &lt;strong&gt;one-shot mode&lt;/strong&gt; — no TUI, no waiting. The agent starts, executes, and exits.&lt;/p&gt;

&lt;p&gt;This is perfect for CI/CD, scheduled tasks, or delegating work you don't want to supervise. Combine it with git worktrees (below) for full isolation, and the agent has zero side effects on your host's working tree.&lt;/p&gt;




&lt;h2&gt;
  
  
  Network Permissions
&lt;/h2&gt;

&lt;p&gt;By default, the agent has unfiltered network access. Define an allowlist and everything else is blocked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api.anthropic.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api.github.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;raw.githubusercontent.com&lt;/span&gt;
    &lt;span class="na"&gt;deny&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;*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proxy runs on the host as a Go HTTP/HTTPS proxy. The container is pointed at it via &lt;code&gt;HTTP_PROXY&lt;/code&gt;/&lt;code&gt;HTTPS_PROXY&lt;/code&gt;. Every request is checked against the allowlist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn Mode
&lt;/h3&gt;

&lt;p&gt;No network rules configured? The proxy runs in &lt;strong&gt;learn mode&lt;/strong&gt; — it records every hostname the agent contacts and prints a suggested allowlist when the session ends:&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="s"&gt;Suggested permissions.network.allow for "claude-dev"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api.anthropic.com&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;raw.githubusercontent.com&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api.github.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add them to your YAML and you're locked down.&lt;/p&gt;




&lt;h2&gt;
  
  
  Git Worktree Isolation
&lt;/h2&gt;

&lt;p&gt;For serious isolation, use &lt;code&gt;--worktree&lt;/code&gt; / &lt;code&gt;-w&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aienv up my-env &lt;span class="nt"&gt;-w&lt;/span&gt; feature/jwt-auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a &lt;strong&gt;git worktree&lt;/strong&gt; — a linked checkout that shares the repo's &lt;code&gt;.git&lt;/code&gt; directory — mounts it into the sandbox as the agent's workspace, and cleans it up when the session ends. Your main working tree stays pristine, and multiple agents can work on different branches simultaneously without interference.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fok4269fkfptnq5472nn0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fok4269fkfptnq5472nn0.jpg" alt=" " width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Audit Trails
&lt;/h2&gt;

&lt;p&gt;Every session produces a JSONL audit log at &lt;code&gt;~/.local/share/aienv/&amp;lt;name&amp;gt;/audit/&amp;lt;session-id&amp;gt;/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;session.meta.json    — env name, agent command, start time
network.jsonl        — every HTTP request and HTTPS CONNECT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each activation gets a unique session ID. Concurrent activations are fully independent. The audit dir is mounted into the container so in-agent scripts can write cost-extraction data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Full Example: Claude Code with Permissions, Worktree, and One-Shot
&lt;/h2&gt;

&lt;p&gt;Here's a complete environment for automated refactoring with Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;env&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;claude-dev&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sandboxed Claude Code for my project&lt;/span&gt;

&lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;npm install -g @anthropic-ai/claude-code&lt;/span&gt;
  &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;claude&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;env:ANTHROPIC_API_KEY"&lt;/span&gt;
    &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;env:GITHUB_TOKEN"&lt;/span&gt;
  &lt;span class="na"&gt;mounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.claude&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.claude&lt;/span&gt;
      &lt;span class="na"&gt;writable&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;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.config/gh&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.config/gh&lt;/span&gt;
      &lt;span class="na"&gt;writable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;deps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;nodejs&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;git&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;gh&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;allow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api.anthropic.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api.github.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;raw.githubusercontent.com&lt;/span&gt;
    &lt;span class="na"&gt;deny&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;*"&lt;/span&gt;

&lt;span class="na"&gt;audit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;persist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;capture&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;network&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Launch it:&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="c"&gt;# Interactive session&lt;/span&gt;
aienv up claude-dev

&lt;span class="c"&gt;# One-shot: refactor and create PR, fully isolated in a worktree&lt;/span&gt;
aienv up claude-dev &lt;span class="nt"&gt;-w&lt;/span&gt; feature/jwt-auth &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"Refactor the auth module to use JWT and create the PR using gh cli"&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Starts in a dedicated git worktree on &lt;code&gt;feature/jwt-auth&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Can only reach Anthropic and GitHub APIs&lt;/li&gt;
&lt;li&gt;Has &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; and &lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt; injected at runtime&lt;/li&gt;
&lt;li&gt;Refactors the auth module, commits, pushes, creates a PR&lt;/li&gt;
&lt;li&gt;Exits. Container removed. Audit logged. Worktree cleaned.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No host contamination. No manual cleanup. Full traceability.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzghyl1sb0ryrs3oj4pyd.jpg" alt=" " width="800" height="420"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Beyond the Basics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trust prompts&lt;/strong&gt; — First activation shows mounts + network rules and asks for confirmation. Cached by YAML hash, re-prompted on config change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debug shell&lt;/strong&gt; — &lt;code&gt;aienv shell &amp;lt;name&amp;gt;&lt;/code&gt; drops you into &lt;code&gt;/bin/bash&lt;/code&gt; inside the sandbox without the agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cleanup&lt;/strong&gt; — &lt;code&gt;aienv clean&lt;/code&gt; removes orphaned Docker images, audit dirs, and trust cache entries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Black-box design&lt;/strong&gt; — Any CLI agent works. Just change &lt;code&gt;agent.install&lt;/code&gt; and &lt;code&gt;agent.command&lt;/code&gt; in YAML. Zero code changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XDG-compliant&lt;/strong&gt; — Config at &lt;code&gt;~/.local/share/aienv/&lt;/code&gt;, trust cache at &lt;code&gt;~/.config/aienv/trust/&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&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;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/kapilratnani/aienv@latest
aienv create my-env
aienv up my-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project is &lt;strong&gt;MIT licensed&lt;/strong&gt;, contributions are welcome, and the architecture decision records are open for discussion.&lt;/p&gt;

&lt;p&gt;Star the repo at &lt;a href="https://github.com/kapilratnani/aienv" rel="noopener noreferrer"&gt;github.com/kapilratnani/aienv&lt;/a&gt;, open an issue if something breaks, and let us know what agents you're running in sandboxes.&lt;/p&gt;

&lt;p&gt;The future of AI coding is isolated, auditable, and reproducible. aienv is a step in that direction.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was written with an AI agent running inside an aienv sandbox. Of course.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>sandbox</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
