<?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: Yuji Suzuki</title>
    <description>The latest articles on DEV Community by Yuji Suzuki (@yujisuzuki).</description>
    <link>https://dev.to/yujisuzuki</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%2F3750795%2Ffc147a96-d3ca-4873-a567-f27aa1edabe7.png</url>
      <title>DEV Community: Yuji Suzuki</title>
      <link>https://dev.to/yujisuzuki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yujisuzuki"/>
    <language>en</language>
    <item>
      <title>The isolation tech behind managed AI sandboxes (gVisor, Firecracker) — worth it locally?</title>
      <dc:creator>Yuji Suzuki</dc:creator>
      <pubDate>Sun, 30 Aug 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/yujisuzuki/the-isolation-tech-behind-managed-ai-sandboxes-gvisor-firecracker-worth-it-locally-4nh0</link>
      <guid>https://dev.to/yujisuzuki/the-isolation-tech-behind-managed-ai-sandboxes-gvisor-firecracker-worth-it-locally-4nh0</guid>
      <description>&lt;p&gt;In Part 1, I laid out three options for where to draw the isolation boundary around an AI coding agent: Claude Code Sandbox, Docker AI Sandboxes, and AI Sandbox + HostMCP (this project). All three run on a normal dev machine with nothing more exotic than Docker or OS-level primitives.&lt;/p&gt;

&lt;p&gt;But if you look at how managed cloud AI agent services isolate &lt;em&gt;their&lt;/em&gt; sandboxes, a different pair of names comes up: gVisor and Firecracker. They're worth understanding on their own terms — and worth asking whether they belong in a local setup too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Isolation technology proper: gVisor and Firecracker
&lt;/h3&gt;

&lt;p&gt;Managed cloud AI agent services that need strong isolation actually use technologies like these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Bedrock AgentCore Code Interpreter&lt;/strong&gt;: a "one-session-one-microVM" model, spinning up a dedicated Firecracker microVM per session (&lt;a href="https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/code-interpreter-session-characteristics.html" rel="noopener noreferrer"&gt;AWS docs&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud GKE Agent Sandbox&lt;/strong&gt;: strong kernel-level isolation via gVisor (&lt;a href="https://docs.cloud.google.com/kubernetes-engine/docs/concepts/machine-learning/agent-sandbox" rel="noopener noreferrer"&gt;Google Cloud docs&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Worth flagging: both of the AWS/Google services above are managed cloud services, not alternatives for a local dev environment. I'm citing them only to show that gVisor/Firecracker are real technologies actually used in production — not to run the same product-level feature comparison I did for Docker AI Sandboxes in Part 1 (they're not in the same product category to begin with).&lt;/p&gt;

&lt;p&gt;Firecracker works by spinning up a single lightweight VM (a microVM) and running code inside it. gVisor works differently — it doesn't create a virtual machine at all. A userspace program called "Sentry" intercepts system calls and reimplements kernel functionality itself to achieve isolation (the process itself runs normally on the host). When Google describes it as "VM-level isolation strength," that's about the strength, not the mechanism — worth keeping straight.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Creates a VM?&lt;/th&gt;
&lt;th&gt;Runs on&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Firecracker (AWS)&lt;/td&gt;
&lt;td&gt;Yes (microVM)&lt;/td&gt;
&lt;td&gt;Linux (requires KVM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gVisor (Google)&lt;/td&gt;
&lt;td&gt;No (intercepts syscalls)&lt;/td&gt;
&lt;td&gt;Linux (as a Docker runtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Using these locally
&lt;/h3&gt;

&lt;p&gt;Both technologies are open source, so they're not cloud-provider-exclusive — you can use them locally too. How easy that is differs a lot between the two.&lt;/p&gt;

&lt;p&gt;gVisor can be used locally just by switching the Docker runtime to &lt;code&gt;runsc&lt;/code&gt;. This raises "process isolation strength" — a different axis from AI Sandbox's "secret hiding via volume mounts" covered in Part 1 — so it's additive, not a replacement. You can check whether it's actually usable in your environment with &lt;code&gt;check-gvisor.sh&lt;/code&gt; (&lt;a href="https://github.com/YujiSuzuki/ai-sandbox/blob/main/.sandbox/host-tools/check-gvisor.sh" rel="noopener noreferrer"&gt;script on GitHub&lt;/a&gt;; a read-only check run on the host OS via HostMCP).&lt;/p&gt;

&lt;p&gt;Firecracker can run locally too, but it needs Linux + KVM plus an integration layer like &lt;code&gt;firecracker-containerd&lt;/code&gt; — switching runtimes alone isn't enough. In practice this becomes "choose an entirely different isolation boundary," putting it closer to the Docker AI Sandboxes product category from Part 1.&lt;/p&gt;

&lt;p&gt;Whether kernel exploits need to be part of your threat model at all also depends on your dev machine's OS.&lt;/p&gt;

&lt;p&gt;On macOS with Docker Desktop/OrbStack, it's easy to forget that containers actually run inside a separate, disposable, lightweight Linux VM — not directly on macOS itself. Even a successful kernel exploit inside a container only compromises that Linux VM directly; reaching macOS itself (the Darwin kernel) would require a separate attack on the hypervisor (a VM escape) as an additional step. In other words, on a Mac dev machine, there's already one extra layer of isolation at work — from Docker Desktop/OrbStack's own implementation — independent of anything AI Sandbox configures. So there's generally little need to add gVisor on a Mac dev machine.&lt;/p&gt;

&lt;p&gt;On Linux with Docker running directly, a kernel exploit inside a container is a direct attack on the host OS kernel. AI Sandbox doesn't specify a runtime in &lt;code&gt;docker-compose.yml&lt;/code&gt;, so it stays on Docker's default &lt;code&gt;runc&lt;/code&gt;, with nothing blocking this path. So on a Linux dev machine, switching the Docker runtime to &lt;code&gt;runsc&lt;/code&gt; (gVisor) is worth considering. As noted above, this is an additive measure on a different axis from secret hiding, and you can check feasibility the same way, with &lt;code&gt;check-gvisor.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because of this difference in baseline exposure, the priority of adding gVisor-based isolation differs between Linux and Mac dev machines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;gVisor and Firecracker solve a real problem — they're what production cloud services reach for when they need strong, kernel-level isolation. But for a local dev machine, whether they're worth adopting depends heavily on your OS: on Linux, &lt;code&gt;runsc&lt;/code&gt; is a cheap, additive check worth running; on macOS, Docker Desktop/OrbStack's own VM boundary already covers most of what you'd gain. Firecracker, meanwhile, is enough of a setup lift that adopting it locally is really "pick a different isolation boundary" rather than a drop-in addition.&lt;/p&gt;

&lt;p&gt;None of this changes the two gaps that AI Sandbox + HostMCP focuses on from Part 1 — filesystem-level secret hiding and controlled cross-container access. gVisor/Firecracker sit on the "process isolation strength" axis; AI Sandbox sits on the "does the AI's filesystem contain secrets at all" axis. They're orthogonal, and you can combine them if your setup calls for it.&lt;/p&gt;

&lt;p&gt;If you haven't read Part 1 yet, it's here: &lt;a href="https://dev.to/yujisuzuki/dont-you-trust-the-ai-vendors-own-sandbox-i-didnt-have-a-good-answer-2k50"&gt;Part 1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/YujiSuzuki/ai-sandbox" rel="noopener noreferrer"&gt;https://github.com/YujiSuzuki/ai-sandbox&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>docker</category>
      <category>security</category>
      <category>linux</category>
    </item>
    <item>
      <title>"Don't you trust the AI vendor's own sandbox?" I didn't have a good answer.</title>
      <dc:creator>Yuji Suzuki</dc:creator>
      <pubDate>Sat, 29 Aug 2026 15:41:02 +0000</pubDate>
      <link>https://dev.to/yujisuzuki/dont-you-trust-the-ai-vendors-own-sandbox-i-didnt-have-a-good-answer-2k50</link>
      <guid>https://dev.to/yujisuzuki/dont-you-trust-the-ai-vendors-own-sandbox-i-didnt-have-a-good-answer-2k50</guid>
      <description>&lt;p&gt;I build an open-source AI sandbox project, and when I mention it to people building products and solutions for a living, I sometimes get this reaction:&lt;/p&gt;

&lt;p&gt;"Don't AI vendors already ship their own sandbox? Don't you trust that?"&lt;/p&gt;

&lt;p&gt;I froze for a second. It's not that I don't trust it. It's that the layer an AI vendor's own sandbox (like Claude Code Sandbox) protects, and the layer my project protects, are simply different things.&lt;/p&gt;

&lt;p&gt;Once you start looking into how to run AI coding agents safely, you keep running into tools with confusingly similar names: Claude Code Sandbox, Docker AI Sandboxes, Docker MCP Toolkit, firejail, gVisor, Firecracker... They all seem to point in the same direction — "isolate the AI agent" — but what they actually protect, and how they work, differ more than you'd expect. This post is my attempt to actually answer that question properly.&lt;/p&gt;

&lt;h3&gt;
  
  
  The short answer: they protect different layers
&lt;/h3&gt;

&lt;p&gt;Here's the comparison up front, as a table.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Claude Code Sandbox&lt;/th&gt;
&lt;th&gt;Docker AI Sandboxes&lt;/th&gt;
&lt;th&gt;AI Sandbox + HostMCP (this project)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Execution restriction&lt;/td&gt;
&lt;td&gt;OS-level&lt;/td&gt;
&lt;td&gt;microVM isolation&lt;/td&gt;
&lt;td&gt;Container isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File-read blocking&lt;/td&gt;
&lt;td&gt;Deny rules (application-level)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Volume mounts (filesystem-level)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-project scope&lt;/td&gt;
&lt;td&gt;Limited (no parent-directory traversal)&lt;/td&gt;
&lt;td&gt;Single workspace&lt;/td&gt;
&lt;td&gt;Whole workspace + per-file hiding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-container access&lt;/td&gt;
&lt;td&gt;Restricted&lt;/td&gt;
&lt;td&gt;Isolated&lt;/td&gt;
&lt;td&gt;Controlled via HostMCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output secret masking&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup validation&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Automatic sync check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup complexity&lt;/td&gt;
&lt;td&gt;None needed on macOS; Linux/WSL2 needs bubblewrap + socat&lt;/td&gt;
&lt;td&gt;Docker Desktop&lt;/td&gt;
&lt;td&gt;Docker + docker-compose&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The point isn't "which one is strongest" — it's that each tool targets a different threat model. Let's go through them one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Code Sandbox — restricts what Bash commands can do
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/sandboxing" rel="noopener noreferrer"&gt;Claude Code Sandbox&lt;/a&gt; uses OS-level primitives (Seatbelt on macOS, Bubblewrap on Linux) to restrict filesystem writes and network access. Adding a Read deny rule in the permission settings also lets you block the AI from reading specific files.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;strength&lt;/strong&gt; here is clear: on macOS it gives you OS-level execution restriction with zero extra setup (Linux/WSL2 needs &lt;code&gt;bubblewrap&lt;/code&gt; and &lt;code&gt;socat&lt;/code&gt; installed). It also cuts down on permission-confirmation friction.&lt;/p&gt;

&lt;p&gt;That said, there are two gaps that aren't covered.&lt;/p&gt;

&lt;p&gt;First, deny rules are an application-level mechanism. They depend both on correct configuration and on the AI tool actually respecting the rule. Worse, these deny rules &lt;a href="https://github.com/anthropics/claude-code/issues/12962" rel="noopener noreferrer"&gt;don't traverse parent directories&lt;/a&gt;. In a monorepo or multi-project workspace, that means one project's config won't protect a sibling project's secrets.&lt;/p&gt;

&lt;p&gt;AI Sandbox sidesteps this at the file level entirely. Each project's secret files are individually hidden from the AI's filesystem via volume mounts, regardless of directory hierarchy. There's no rule to traverse in the first place — the idea is that the rule shouldn't need to exist.&lt;/p&gt;

&lt;p&gt;Second, there's friction with Docker commands. Docker commands need direct access to the Docker socket, which is structurally incompatible with the sandboxing mechanism. In fact, &lt;a href="https://code.claude.com/docs/en/sandboxing#troubleshooting" rel="noopener noreferrer"&gt;Claude Code Sandbox's own troubleshooting docs&lt;/a&gt; recommend adding &lt;code&gt;docker *&lt;/code&gt; to &lt;code&gt;excludedCommands&lt;/code&gt; (i.e., excluding it from the sandbox). The result: Docker operations run with unrestricted host privileges, entirely outside the sandbox's protection.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Aside: firejail&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On Linux, &lt;a href="https://firejail.wordpress.com/" rel="noopener noreferrer"&gt;firejail&lt;/a&gt; often comes up in comparisons. It sandboxes at the &lt;strong&gt;process level&lt;/strong&gt; using Linux namespaces — the same category as the bubblewrap that Claude Code Sandbox uses. Unlike this project's approach of carving out the AI agent's entire execution environment, firejail is meant to nest inside a larger sandbox.&lt;/p&gt;

&lt;p&gt;On the narrow question of "hiding secrets," though, it's a different story. firejail's &lt;code&gt;--blacklist&lt;/code&gt; option denies access to target paths at the OS kernel level. According to &lt;a href="https://man.archlinux.org/man/firejail.1.en" rel="noopener noreferrer"&gt;firejail's own docs&lt;/a&gt;, blacklisted files/directories "remain visible in the filesystem, but become completely inaccessible." I couldn't confirm from public docs whether the underlying implementation is bind-mount-based, but in the sense that it doesn't depend on the AI tool respecting a rule, it's closer in spirit to AI Sandbox's volume-mount approach than to application-level deny rules (though the AI-facing appearance may differ — AI Sandbox shows empty files/directories, which may not be exactly how firejail presents it).&lt;/p&gt;

&lt;p&gt;That said, firejail is limited to a single process, isn't designed to treat a whole multi-project workspace as one unit, and doesn't cover controlled access to other containers. It's Linux-only, so it's not available on macOS, which is AI Sandbox's primary target. On a Linux dev machine specifically, &lt;code&gt;--blacklist&lt;/code&gt; alone could plausibly reproduce secret-hiding on its own, but it doesn't cover the rest.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Docker AI Sandboxes — isolates everything inside a microVM
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/ai/sandboxes" rel="noopener noreferrer"&gt;Docker AI Sandboxes&lt;/a&gt; runs the AI agent inside an isolated microVM with its own Docker daemon. The agent can't touch the host system at all.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;strength&lt;/strong&gt;: strong microVM-based isolation, full autonomy for the AI agent inside the sandbox, and each sandbox gets its own Docker daemon.&lt;/p&gt;

&lt;p&gt;There are two &lt;strong&gt;gaps&lt;/strong&gt;. It syncs the entire workspace directory into the microVM, with no mechanism to exclude specific files — so &lt;code&gt;.env&lt;/code&gt; files are plainly visible from the inside. This isn't a flaw so much as a difference in design goals: Docker AI Sandboxes exists to "protect the host from the AI agent's execution," not to "hide secrets from the AI." The other gap: because it's fully isolated, a sandbox can't talk to other containers, which rules out cross-container debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker MCP Toolkit — focused on isolating MCP servers
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.docker.com/blog/mcp-toolkit-mcp-servers-that-just-work/" rel="noopener noreferrer"&gt;Docker MCP Toolkit&lt;/a&gt; provides 200+ containerized MCP servers with built-in isolation and secret management. Its strengths are a rich catalog of pre-built MCP servers and built-in secret management for MCP server configuration.&lt;/p&gt;

&lt;p&gt;But this tool is focused on isolating MCP servers — hiding project-level secrets from the AI is out of scope. It doesn't address &lt;code&gt;.env&lt;/code&gt; files or private keys sitting in your source tree.&lt;/p&gt;

&lt;h3&gt;
  
  
  The two gaps AI Sandbox fills
&lt;/h3&gt;

&lt;p&gt;Given the comparison so far, AI Sandbox + HostMCP can be summarized as filling two specific gaps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gap 1: Filesystem-level secret hiding&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of blocking access to secrets via rules (which can be misconfigured or bypassed), Docker volume mounts physically remove secrets from the AI's filesystem.&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;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/null:/workspace/my-app/.env:ro&lt;/span&gt;         &lt;span class="c1"&gt;# appears as an empty file to the AI&lt;/span&gt;
&lt;span class="na"&gt;tmpfs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/workspace/my-app/secrets&lt;/span&gt;  &lt;span class="c1"&gt;# appears as an empty directory to the AI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Secrets don't exist in the AI's world at all. Not blocked by a rule, not filtered by a config — they're simply not there. The application container, meanwhile, mounts the real files as usual.&lt;/p&gt;

&lt;p&gt;As a safeguard against misconfiguration, the sandbox runs a validation check at startup to confirm the AI tool's deny rules stay in sync with the volume mounts in &lt;code&gt;docker-compose.yml&lt;/code&gt;. If a secret file is only configured on one side, a warning fires before the AI can access it. A separate check also scans for secret-looking files that aren't hidden in &lt;code&gt;docker-compose.yml&lt;/code&gt;, every time an AI session starts. This catches configuration gaps early for files created mid-development, and the AI itself asks the user how to handle a flagged file — whether it actually needs hiding or is fine to leave as-is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gap 2: Controlled cross-container access&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HostMCP acts as a gateway between AI Sandbox and Docker containers, enforcing a security policy. The AI can read logs, run whitelisted commands, and inspect containers — but can't access blocked paths or run arbitrary commands. Starting/stopping containers is disabled by default and only works if explicitly enabled in config. Sensitive data (passwords, API keys, tokens) is automatically masked in output, and HostMCP itself binds only to loopback (127.0.0.1) by default, so it's not reachable from other machines on the network out of the box.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layering these tools together
&lt;/h3&gt;

&lt;p&gt;So far this has been framed as "versus," but in practice these tools sort into two layers with different properties, and thinking of it that way clarifies where each one fits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Isolation boundary: something you &lt;em&gt;choose&lt;/em&gt; based on your threat model&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Docker AI Sandboxes and AI Sandbox both answer the question "where do you draw the line around the AI agent's entire execution environment?" The former uses a microVM; the latter uses containers plus volume-mount-based secret removal. Since their roles overlap, they're not meant to be stacked — you pick one based on your threat model.&lt;/p&gt;

&lt;p&gt;Claude Code Sandbox targets something different — it only restricts Bash command execution at the OS level — so it can be nested inside whichever outer environment you chose. That said, when nesting inside an unprivileged container like AI Sandbox, bubblewrap can fail to mount a fresh &lt;code&gt;/proc&lt;/code&gt;, per the &lt;a href="https://code.claude.com/docs/en/sandboxing#troubleshooting" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;, requiring &lt;code&gt;enableWeakerNestedSandbox&lt;/code&gt; — in which case the nested sandbox's process-space isolation ends up depending on the outer container boundary instead (the permission deny rules themselves are unaffected and keep working). So it's not quite true that "nesting inside AI Sandbox gets you maximum protection" — there's an added benefit, but it's limited.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Isolation boundary option&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code Sandbox&lt;/td&gt;
&lt;td&gt;Restricts Bash command execution at the OS level (nestable inside other boundaries, with the caveat above)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker AI Sandboxes&lt;/td&gt;
&lt;td&gt;Isolates the whole AI agent in a microVM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Sandbox (this project)&lt;/td&gt;
&lt;td&gt;Container isolation + volume mounts to remove secrets from the AI's filesystem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you're curious how these boundaries relate to the kernel-level isolation tech (gVisor, Firecracker) that managed cloud AI services use, and whether it's worth adopting locally, I cover that in Part 2 — it's a tangent from AI Sandbox's own scope, so I split it out to keep this post focused.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Permission layer: usable independently, alongside anything above&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HostMCP's cross-container access control and Managed Settings' deny rules sit at a different layer from the isolation boundary. They control access at the level of individual tool calls, so they can be layered independently on top of whichever isolation boundary you pick above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;"How should you isolate an AI agent?" doesn't have a single right answer. Claude Code Sandbox restricts command execution, Docker AI Sandboxes isolates everything inside a microVM, and gVisor/Firecracker are used in production as even stronger isolation technologies in the cloud. Each protects a different layer, against a different threat model.&lt;/p&gt;

&lt;p&gt;What AI Sandbox + HostMCP chose to focus on is: physically erasing secrets at the filesystem level, and safely bridging cross-container access behind an approval flow. It's built specifically to fill those two gaps, and designed to be additive — not in competition with the other isolation boundaries or permission layers above.&lt;/p&gt;

&lt;p&gt;Safe AI-driven development needs both: protecting secrets, and not getting in the way of the humans and AI actually doing the work. AI Sandbox is built to try to hold both of those at once.&lt;/p&gt;

&lt;p&gt;If you've ever looked at your own dev setup and thought "wait, is the AI reading my private keys too?" — take a look at the repo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/YujiSuzuki/ai-sandbox" rel="noopener noreferrer"&gt;https://github.com/YujiSuzuki/ai-sandbox&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>docker</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>One Repo Became Three — Quietly, Then Publicl</title>
      <dc:creator>Yuji Suzuki</dc:creator>
      <pubDate>Tue, 28 Jul 2026 16:56:47 +0000</pubDate>
      <link>https://dev.to/yujisuzuki/one-repo-became-three-quietly-then-publicl-4ofd</link>
      <guid>https://dev.to/yujisuzuki/one-repo-became-three-quietly-then-publicl-4ofd</guid>
      <description>&lt;h1&gt;
  
  
  One Repo Became Three — Quietly, Then Publicly
&lt;/h1&gt;

&lt;h1&gt;
  
  
  ai #docker #security #mcp
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Previously
&lt;/h2&gt;

&lt;p&gt;Back in February, I published &lt;a href="https://dev.to/yujisuzuki/official-ai-sandboxes-arrived-why-i-published-mine-anyway-50n7"&gt;AI Sandbox Environment + DockMCP&lt;/a&gt; — a single repo that isolated AI coding agents in a Docker container, hid &lt;code&gt;.env&lt;/code&gt; files and secrets at the filesystem level, and gave AI a controlled path back out to other containers through an MCP server.&lt;/p&gt;

&lt;p&gt;Structurally, though, it was three different jobs wearing one trench coat: a devcontainer template, a host-side MCP server, and an in-container script/tool discovery server. I said I'd eventually split them apart. What I didn't say at the time was what I was about to use the split version &lt;em&gt;for&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Quiet Part
&lt;/h2&gt;

&lt;p&gt;Before any of this was public, I split &lt;code&gt;ai-sandbox-dkmcp&lt;/code&gt; into three repos privately and used that setup to build and ship an actual product: &lt;a href="https://apps.apple.com/jp/app/tokeruyo/id6759848796" rel="noopener noreferrer"&gt;Tokeruyo&lt;/a&gt;, an iOS app.&lt;/p&gt;

&lt;p&gt;Building a real iOS app inside the sandbox — not a demo, not the SecureNote sample app — surfaced friction that a template alone never would have. Xcode builds and tests don't run inside a Linux container; they need the host OS. That meant the host-tools mechanism, which had been a minor feature for wrapping &lt;code&gt;docker-compose up&lt;/code&gt;, suddenly had to carry real weight:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;xcode-build.sh&lt;/code&gt;, &lt;code&gt;xcode-test.sh&lt;/code&gt;, &lt;code&gt;xcode-archive.sh&lt;/code&gt; — host tools that let AI kick off Xcode operations without leaving the sandbox&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;per-tool timeout declaration&lt;/strong&gt; (&lt;code&gt;# @timeout: 600&lt;/code&gt; in a script's header). The global timeout was 60 seconds, fine for something like &lt;code&gt;docker-compose up&lt;/code&gt; — and &lt;code&gt;xcode-test.sh&lt;/code&gt; blew right through it. The fix wasn't obvious on the first try; it took some back-and-forth with Claude Code, weighing "just raise the global default" against "let a tool declare its own ceiling," before landing on the per-tool declaration (still clamped by an admin-controlled max, so a script can't unilaterally claim an hour).&lt;/li&gt;
&lt;li&gt;Generic &lt;code&gt;docker-compose-up.sh&lt;/code&gt; / &lt;code&gt;-down.sh&lt;/code&gt; / &lt;code&gt;-build.sh&lt;/code&gt; wrappers, once one-off demo scripts, made reusable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this was designed up front. It's the residue of actually depending on the tool to ship something, not just to demo it. If you look at &lt;a href="https://github.com/YujiSuzuki/ai-sandbox/blob/main/docs/host-access.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/host-access.md&lt;/code&gt;&lt;/a&gt; in the ai-sandbox repo today, the Xcode tools and the &lt;code&gt;@timeout&lt;/code&gt; mechanism are still sitting there — leftovers from that period, kept because they turned out to be generally useful.&lt;/p&gt;

&lt;p&gt;The app shipped. That felt like a natural stopping point.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Public Part
&lt;/h2&gt;

&lt;p&gt;With the app out, I published the three-way split for real:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;Runs where&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/YujiSuzuki/ai-sandbox" rel="noopener noreferrer"&gt;&lt;strong&gt;ai-sandbox&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;The devcontainer template — secret hiding, project structure, slash commands&lt;/td&gt;
&lt;td&gt;Docker (VS Code / CLI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/YujiSuzuki/hostmcp" rel="noopener noreferrer"&gt;&lt;strong&gt;hostmcp&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;MCP server for host-side access — containers, host tools, host OS commands&lt;/td&gt;
&lt;td&gt;Host OS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/YujiSuzuki/sandbox-mcp" rel="noopener noreferrer"&gt;&lt;strong&gt;sandbox-mcp&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Lightweight MCP server for script/tool discovery inside the container&lt;/td&gt;
&lt;td&gt;Inside the container (stdio)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;DockMCP&lt;/code&gt; became &lt;strong&gt;HostMCP&lt;/strong&gt;. The bundled tool-discovery layer became &lt;strong&gt;SandboxMCP&lt;/strong&gt;. What's left of the original repo is just &lt;strong&gt;AI Sandbox&lt;/strong&gt; — the template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Sandbox (container)
  └─ SandboxMCP (stdio)          ← discovers .sandbox/scripts/ and .sandbox/tools/
  └─ hostmcp client (via HTTP)   ← talks to HostMCP on the host OS
        ↓
Host OS: HostMCP server → API container, DB container, host tools, …
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Publishing didn't stop the work, either. HostMCP picked up a proper installer (&lt;code&gt;go install github.com/YujiSuzuki/hostmcp@latest&lt;/code&gt;), host-path masking so the home directory's username never leaks into what AI sees, a "dangerous mode" for read-only debugging commands that still respects blocked paths, and large-output handling so a runaway build log doesn't blow out the context window. SandboxMCP picked up nested-git-repo detection for multi-repo workspaces. It's settled into a steady state now, which is why this post exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Split at All
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Independent installs.&lt;/strong&gt; Someone with an existing devcontainer might want HostMCP for host access, or SandboxMCP for script discovery, without adopting the whole secret-hiding template. As one repo, that meant cloning the template and cherry-picking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Independent release cadence.&lt;/strong&gt; HostMCP being &lt;code&gt;go install&lt;/code&gt;-able shouldn't be gated behind a template release. It's a HostMCP concern now, not an ai-sandbox concern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real usage exposes real seams.&lt;/strong&gt; The Xcode host tools and per-tool timeouts didn't come from design — they came from hitting a wall while shipping an actual app. Having HostMCP as its own project made it obvious that "host tools" needed to support more than the couple of demo scripts it launched with.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Didn't Change
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Secrets are physically absent, not rule-blocked.&lt;/strong&gt; &lt;code&gt;.env&lt;/code&gt; files and private keys still don't exist in AI's filesystem — not hidden by a deny list, just not there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI observes, humans act on infrastructure.&lt;/strong&gt; HostMCP still won't let AI rebuild an image or run &lt;code&gt;docker-compose up&lt;/code&gt; directly on its own judgment; that has to go through an approved host tool, and approval is a human step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Still just Docker + MCP.&lt;/strong&gt; No lock-in to a specific AI tool. Claude Code, Gemini CLI, Claude Desktop via MCP — all of it works the same way it did as one repo.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Setting up a new project? Start with &lt;a href="https://github.com/YujiSuzuki/ai-sandbox" rel="noopener noreferrer"&gt;&lt;strong&gt;ai-sandbox&lt;/strong&gt;&lt;/a&gt; — click "Use this template."&lt;/li&gt;
&lt;li&gt;Already have a devcontainer and just want host access? &lt;a href="https://github.com/YujiSuzuki/hostmcp" rel="noopener noreferrer"&gt;&lt;strong&gt;hostmcp&lt;/strong&gt;&lt;/a&gt; installs standalone.&lt;/li&gt;
&lt;li&gt;Want AI to discover your own scripts and tools without re-explaining them every session? &lt;a href="https://github.com/YujiSuzuki/sandbox-mcp" rel="noopener noreferrer"&gt;&lt;strong&gt;sandbox-mcp&lt;/strong&gt;&lt;/a&gt; is a &lt;code&gt;go install&lt;/code&gt; away.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback and issues are welcome on any of the three repos.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>docker</category>
      <category>security</category>
      <category>mcp</category>
    </item>
    <item>
      <title>My AI Escaped Its Container and Did Everything — Except Review Its Own Code</title>
      <dc:creator>Yuji Suzuki</dc:creator>
      <pubDate>Tue, 17 Feb 2026 15:23:49 +0000</pubDate>
      <link>https://dev.to/yujisuzuki/my-ai-escaped-its-container-and-did-everything-except-review-its-own-code-388o</link>
      <guid>https://dev.to/yujisuzuki/my-ai-escaped-its-container-and-did-everything-except-review-its-own-code-388o</guid>
      <description>&lt;h2&gt;
  
  
  Previously: The Complete Dev Cycle
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/yujisuzuki/my-ai-broke-out-of-its-container-and-i-let-it-4dkh"&gt;Part 4 of this series&lt;/a&gt;, my AI assistant achieved something remarkable. Running inside a secure Docker container, it could now execute the entire development cycle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code → Test → Build → Deploy → Commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I called it the finale. The trilogy was complete. The AI could write code, run tests, build artifacts, deploy to containers, and commit changes — all while keeping secrets safely hidden.&lt;/p&gt;

&lt;p&gt;I was wrong. Something was missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Missing Piece
&lt;/h2&gt;

&lt;p&gt;Look at that cycle again. Now think about how a real development team works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code → Test → Build → Deploy → Commit → PR → ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where's the review?&lt;/p&gt;

&lt;p&gt;In any professional team, code doesn't just flow from writing to deployment. Someone reads it. Someone checks for bugs, security issues, architectural problems. Someone asks "did you consider this edge case?"&lt;/p&gt;

&lt;p&gt;My AI could do everything — except check its own work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Official Plugin
&lt;/h2&gt;

&lt;p&gt;Claude Code has an official &lt;a href="https://github.com/anthropics/claude-code/blob/main/plugins/code-review/commands/code-review.md" rel="noopener noreferrer"&gt;&lt;code&gt;/code-review&lt;/code&gt; plugin&lt;/a&gt;. When I discovered it, I was impressed by its design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parallel agents&lt;/strong&gt;: Multiple AI agents analyze code simultaneously from different angles — bug scanning, CLAUDE.md compliance checking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidence scoring&lt;/strong&gt;: Each finding gets a score, filtering out noise&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification step&lt;/strong&gt;: A separate agent re-checks findings to eliminate false positives&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is serious engineering. Not "ask AI to review code" but a structured, multi-stage pipeline designed to produce high-signal results.&lt;/p&gt;

&lt;p&gt;I installed it immediately.&lt;/p&gt;

&lt;p&gt;And it didn't work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Couldn't Reach
&lt;/h2&gt;

&lt;p&gt;The official plugin is designed for a standard GitHub workflow. It expects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;gh&lt;/code&gt; CLI&lt;/strong&gt; — to fetch PR details from GitHub&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A GitHub PR&lt;/strong&gt; — the review target is a pull request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A single repository&lt;/strong&gt; — it operates within one project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My AI Sandbox environment has none of that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No &lt;code&gt;gh&lt;/code&gt; CLI (the container has no GitHub authentication)&lt;/li&gt;
&lt;li&gt;No PR yet (I want review &lt;em&gt;before&lt;/em&gt; pushing, not after)&lt;/li&gt;
&lt;li&gt;Multiple independent repositories in one workspace (API, Web, iOS — each with their own Git history)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The plugin couldn't reach my code. Not because it was poorly designed — it's excellent at what it does. But it was built for a different moment in the development cycle: &lt;strong&gt;after&lt;/strong&gt; you push. I needed something &lt;strong&gt;before&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning From the Design
&lt;/h2&gt;

&lt;p&gt;I couldn't use the plugin directly, but I could learn from it.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/anthropics/claude-code/blob/main/plugins/README.md" rel="noopener noreferrer"&gt;plugins documentation&lt;/a&gt; showed me that Claude Code's custom commands are just Markdown files — structured instructions that become slash commands. The official &lt;code&gt;/code-review&lt;/code&gt; demonstrated what a well-designed review pipeline looks like: parallel analysis, scoring, verification.&lt;/p&gt;

&lt;p&gt;So I did what my AI Sandbox was built for. I asked the AI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Analyze the code-review plugin and create a custom command that works locally. Allow selecting which project to review. Confirm the target branch with the user. Run the same kind of review, but without GitHub access.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AI read the official plugin, understood its structure, and produced a local version. No &lt;code&gt;gh&lt;/code&gt; dependency. Multi-project support. Git and non-Git modes.&lt;/p&gt;

&lt;p&gt;It worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  From One to Nine
&lt;/h2&gt;

&lt;p&gt;Once the local review command was running, the next thought was obvious.&lt;/p&gt;

&lt;p&gt;If I can have a general code reviewer, why not a security reviewer? A performance reviewer? An architecture reviewer?&lt;/p&gt;

&lt;p&gt;Each review type needs different expertise. A security review looks for injection vulnerabilities, authentication gaps, and data exposure. A performance review looks for N+1 queries, unnecessary allocations, and missing caching. A general review catches bugs and checks CLAUDE.md compliance.&lt;/p&gt;

&lt;p&gt;One command became nine:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ais-local-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;General code review (bugs, CLAUDE.md)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ais-local-security-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Security vulnerabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ais-local-performance-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Performance bottlenecks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ais-local-architecture-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Structural concerns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ais-local-test-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Test quality assessment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ais-local-doc-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Documentation accuracy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ais-local-prompt-review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;AI prompt/command quality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ais-refactor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Concrete refactoring suggestions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ais-test-gen&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Automated test generation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All nine share the same pipeline architecture inspired by the official plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Parallel Analysis → Scoring → Verification → Report
(4-5 Sonnet agents)  (Haiku)   (Sonnet)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each specialized command sends parallel agents with different review perspectives. A scoring agent evaluates confidence. A verification agent eliminates false positives. Only high-confidence, verified findings make it to the final report.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pipeline in Action
&lt;/h2&gt;

&lt;p&gt;Here's what happens when you run &lt;code&gt;/ais-local-review&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: Select a project and branch (or files, if no Git)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Four Sonnet agents launch in parallel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent #1: CLAUDE.md compliance — does the code follow project conventions?&lt;/li&gt;
&lt;li&gt;Agent #2: Bug scan — obvious logic errors, edge cases&lt;/li&gt;
&lt;li&gt;Agent #3: History analysis — are we reintroducing a previously fixed bug?&lt;/li&gt;
&lt;li&gt;Agent #4: Comment check — does the code match its own documentation?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: A Haiku agent scores every finding (0-100)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: A Sonnet verification agent re-checks anything scoring 75+&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5&lt;/strong&gt;: Only confirmed, high-confidence issues appear in the report&lt;/p&gt;

&lt;p&gt;The result is a focused report. Not a wall of nitpicks — a short list of things that actually matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Reviews, Two Moments
&lt;/h2&gt;

&lt;p&gt;Here's what's interesting: the official plugin and my local commands aren't competing. They serve different moments in the development cycle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code → Review → Test → Build → Deploy → Commit → PR → Review
         ↑                                                ↑
    ais-* commands                              Official /code-review
    Before you push                              After you push
    Quality gate                                 Team review
    Local, private                               GitHub, collaborative
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The official &lt;code&gt;/code-review&lt;/code&gt; is for when your code is ready for team eyes. It posts comments on PRs, suggests changes, integrates with GitHub's collaboration features.&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;ais-*&lt;/code&gt; commands are for before that moment. While you're still developing. Before you've committed, sometimes before you've even finished writing tests. A private quality gate that catches issues early, when they're cheapest to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Completed Cycle
&lt;/h2&gt;

&lt;p&gt;Remember the development cycle from Part 4?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code → Test → Build → Deploy → Commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what it looks like now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code → Review → Test → Build → Deploy → Commit
         ↑
    The missing piece
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI can write code, review its own work (from multiple perspectives), run tests, build, deploy, and commit. The quality gate that was missing is now in place.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;This project started because the official plugin couldn't reach my code. But that limitation led somewhere unexpected.&lt;/p&gt;

&lt;p&gt;The official plugin's design — parallel agents, confidence scoring, false positive elimination — was the blueprint. Open source at its best: you read how something works, understand the principles, and adapt them to your environment.&lt;/p&gt;

&lt;p&gt;I didn't just get a code reviewer. I got nine specialized review tools, a refactoring assistant, and an automated test generator. All because the official plugin showed me what a well-designed review pipeline looks like, and my AI Sandbox gave me a place to build one that works locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Series So Far
&lt;/h2&gt;

&lt;p&gt;What started as "my AI can see my API keys" has become something larger:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/yujisuzuki/your-ai-assistant-can-see-your-secrets-heres-how-i-fixed-it-19lj"&gt;Secrets&lt;/a&gt;&lt;/strong&gt;: Hide sensitive files from AI using Docker volume mounts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/yujisuzuki/i-gave-my-ai-a-toolbox-it-surprised-me-by-using-it-4on2"&gt;Toolbox&lt;/a&gt;&lt;/strong&gt;: AI discovers and uses tools autonomously via SandboxMCP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://dev.to/yujisuzuki/my-ai-broke-out-of-its-container-and-i-let-it-4dkh"&gt;Host Access&lt;/a&gt;&lt;/strong&gt;: AI breaks out of its container with controlled host OS access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review&lt;/strong&gt; (this article): AI reviews its own code, completing the dev cycle&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The trilogy became a tetralogy. I'll stop promising it's complete.&lt;/p&gt;




&lt;p&gt;The AI Sandbox with DockMCP is open source: &lt;a href="https://github.com/yujiosaka/ai-sandbox-with-dockmcp" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you've built custom review commands for your AI workflow, I'd love to hear about it in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>docker</category>
      <category>security</category>
    </item>
    <item>
      <title>My AI Broke Out of Its Container — And I Let It</title>
      <dc:creator>Yuji Suzuki</dc:creator>
      <pubDate>Sun, 15 Feb 2026 15:56:36 +0000</pubDate>
      <link>https://dev.to/yujisuzuki/my-ai-broke-out-of-its-container-and-i-let-it-4dkh</link>
      <guid>https://dev.to/yujisuzuki/my-ai-broke-out-of-its-container-and-i-let-it-4dkh</guid>
      <description>&lt;h2&gt;
  
  
  Previously, on AI Sandbox...
&lt;/h2&gt;

&lt;p&gt;If you've been following along, you know the story:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/yujisuzuki/your-ai-assistant-can-see-your-secrets-heres-how-i-fixed-it-19lj"&gt;Part 1&lt;/a&gt;:&lt;/strong&gt; I discovered my AI assistant was reading my API keys. I built a Docker sandbox that hides secrets via volume mounts — files appear empty to AI, but application containers still have full access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/yujisuzuki/i-gave-my-ai-a-toolbox-it-surprised-me-by-using-it-4on2"&gt;Part 2&lt;/a&gt;:&lt;/strong&gt; I gave the sandboxed AI a toolbox (SandboxMCP). It surprised me by autonomously discovering a forgotten tool and repurposing it to solve a problem I hadn't anticipated.&lt;/p&gt;

&lt;p&gt;Now for the final chapter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Last Wall
&lt;/h2&gt;

&lt;p&gt;After Parts 1 and 2, my AI assistant could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Read and edit all source code&lt;/li&gt;
&lt;li&gt;✅ Check container logs via DockMCP&lt;/li&gt;
&lt;li&gt;✅ Run tests inside containers&lt;/li&gt;
&lt;li&gt;✅ Discover and use tools autonomously&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But there was one thing it still couldn't do:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anything that required the host OS.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Start the demo app" → Sorry, I can't run docker-compose.
"Build the containers" → I don't have access to Docker.
"Commit this change" → I can commit, but the message style...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every time I needed to build, deploy, or manage containers, I had to switch to my terminal and do it myself. The AI was powerful inside its box, but the box was still a box.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Uncomfortable Question
&lt;/h2&gt;

&lt;p&gt;Here's the thing about containers: they're designed to isolate. That's their entire purpose. Giving a sandboxed AI access to the host OS sounds like... undoing the sandbox.&lt;/p&gt;

&lt;p&gt;I sat with this tension for a while. The whole point of AI Sandbox was &lt;strong&gt;security&lt;/strong&gt; — hiding secrets, controlling access, preventing accidents. How do you extend reach without breaking trust?&lt;/p&gt;

&lt;p&gt;The answer turned out to be the same pattern I'd used twice before: &lt;strong&gt;don't give access, give a controlled interface.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Part 1: Don't give AI your secrets → Give it DockMCP to read logs and run tests&lt;/li&gt;
&lt;li&gt;Part 2: Don't install tools for AI → Let it discover what's available&lt;/li&gt;
&lt;li&gt;Part 3: Don't give AI the host OS → Give it &lt;strong&gt;approved scripts&lt;/strong&gt; it can run through a gateway&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Host Access Works
&lt;/h2&gt;

&lt;p&gt;The architecture is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Sandbox (container)
  │
  │  MCP / HTTP
  ▼
DockMCP Server (host OS)
  ├── Container access     ← existing (logs, exec, stats)
  ├── Host Tools           ← NEW: run approved scripts
  ├── Container Lifecycle  ← NEW: start/stop/restart
  └── Host Commands        ← NEW: whitelisted CLI commands
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the interesting part isn't the architecture — it's the approval workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Two-Stage Approval
&lt;/h3&gt;

&lt;p&gt;AI (or developers) can propose a new host tool by placing a script in &lt;code&gt;.sandbox/host-tools/&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;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# demo-up.sh&lt;/span&gt;
&lt;span class="c"&gt;# Start demo application containers&lt;/span&gt;
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; demo-apps/docker-compose.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this script &lt;strong&gt;cannot run yet&lt;/strong&gt;. It's in staging — inside the workspace where AI can write files.&lt;/p&gt;

&lt;p&gt;To activate it, the human runs &lt;code&gt;dkmcp tools sync&lt;/code&gt; on the host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dkmcp tools sync

📋 Reviewing tools from .sandbox/host-tools/:

  demo-up.sh (NEW)
    Start demo application containers
    ─────────────────────────────
    #!/bin/bash
    docker compose -f demo-apps/docker-compose.yml up -d
    ─────────────────────────────
    Approve? [y/N]: y
    ✅ Approved → ~/.dkmcp/host-tools/myproject/demo-up.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the &lt;strong&gt;approved copy&lt;/strong&gt; runs. If AI modifies the staging version later, &lt;code&gt;dkmcp tools sync&lt;/code&gt; detects the SHA256 mismatch and prompts for re-approval.&lt;/p&gt;

&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI can &lt;strong&gt;propose&lt;/strong&gt; tools (creative freedom)&lt;/li&gt;
&lt;li&gt;Humans &lt;strong&gt;approve&lt;/strong&gt; tools (security control)&lt;/li&gt;
&lt;li&gt;Only approved versions &lt;strong&gt;execute&lt;/strong&gt; (integrity guarantee)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Changed in Practice
&lt;/h2&gt;

&lt;p&gt;Before v0.5.x, a typical conversation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Start the demo app.&lt;br&gt;
&lt;strong&gt;AI:&lt;/strong&gt; I can't run docker-compose from inside the container. Please run this on your terminal:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose -f demo-apps/docker-compose.yml up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;After v0.5.x:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Start the demo app.&lt;br&gt;
&lt;strong&gt;AI:&lt;/strong&gt; &lt;em&gt;[calls &lt;code&gt;run_host_tool&lt;/code&gt; with &lt;code&gt;demo-up.sh&lt;/code&gt;]&lt;/em&gt;&lt;br&gt;
Demo containers started. API is at :3000, Web at :3001.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The difference seems small. But multiply it across every build, every restart, every deployment — and the friction adds up. The AI went from being a helpful advisor that tells you &lt;em&gt;what&lt;/em&gt; to type, to a capable agent that &lt;em&gt;does&lt;/em&gt; the thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Commit Workflow (A Small Thing That Matters)
&lt;/h2&gt;

&lt;p&gt;One more thing that came together in this release. I built a commit message script (&lt;code&gt;commit-msg.sh&lt;/code&gt;) that creates a collaborative workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate draft from staged changes → Check previous commit style → Refine together → Commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what it looks like in practice:&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="nv"&gt;$ &lt;/span&gt;.sandbox/scripts/commit-msg.sh              &lt;span class="c"&gt;# Generate draft from git diff&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;.sandbox/scripts/commit-msg.sh &lt;span class="nt"&gt;--log&lt;/span&gt;        &lt;span class="c"&gt;# Check how recent commits read&lt;/span&gt;
&lt;span class="c"&gt;# ... AI and human refine CommitMsg-draft.md together ...&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;.sandbox/scripts/commit-msg.sh &lt;span class="nt"&gt;--msg-file&lt;/span&gt; CommitMsg-draft.md  &lt;span class="c"&gt;# Commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interesting discovery: the script itself always had a &lt;code&gt;--log&lt;/code&gt; option to check previous style, but AI wasn't using it. The fix wasn't changing the script — it was writing the full three-step workflow in the AI instruction file (CLAUDE.md). Once AI could &lt;em&gt;see&lt;/em&gt; the steps laid out explicitly, it followed them perfectly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want AI to follow a workflow, don't just give it a tool — spell out the steps.&lt;/strong&gt; The tool can be perfectly designed, but AI won't discover optional flags on its own. This applies to any AI coding assistant, not just this project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trilogy Arc
&lt;/h2&gt;

&lt;p&gt;Looking back, there's a clear progression:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;What AI Could Do&lt;/th&gt;
&lt;th&gt;What It Couldn't&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;v0.1: Protect&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Read code&lt;/td&gt;
&lt;td&gt;See secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;v0.3: Equip&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Discover and use tools&lt;/td&gt;
&lt;td&gt;Touch the host OS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;v0.5: Unleash&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Run host scripts, manage containers&lt;/td&gt;
&lt;td&gt;&lt;em&gt;(nothing that matters for daily dev)&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The sandbox started as a cage. Then it became a workshop. Now it's a full development environment — with the security model still intact.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Secrets? Still hidden (volume mounts haven't changed).
Container access? Still controlled (whitelist, output masking).
Host access? Controlled too (approval workflow, SHA256 verification).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every layer of capability was added &lt;strong&gt;on top of&lt;/strong&gt; the security foundation, never at the expense of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is This the End?
&lt;/h2&gt;

&lt;p&gt;For the core functionality — yes. My personal development workflow is now complete:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code → Test → Build → Deploy → Commit → Code → ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full loop. All within the sandbox.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AI reads and writes code (sandbox)&lt;/li&gt;
&lt;li&gt;AI checks logs and runs tests (DockMCP container access)&lt;/li&gt;
&lt;li&gt;AI discovers and uses tools (SandboxMCP)&lt;/li&gt;
&lt;li&gt;AI builds, deploys, and manages containers (DockMCP host access)&lt;/li&gt;
&lt;li&gt;AI drafts commit messages collaboratively (commit-msg.sh)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There's nothing left in my daily workflow that requires me to switch to a terminal and do things manually.&lt;/p&gt;

&lt;p&gt;Well, except &lt;code&gt;dkmcp tools sync&lt;/code&gt;. That one stays manual — by design.&lt;/p&gt;

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

&lt;p&gt;The template is open source. You can set up the entire environment in about 10 minutes:&lt;/p&gt;

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

&lt;p&gt;It works with Claude Code, Gemini CLI, and any MCP-compatible AI tool. If you're running AI coding assistants and haven't thought about where your secrets go — now's a good time.&lt;/p&gt;

&lt;p&gt;If you find it useful, a star on GitHub would mean a lot.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is Part 3 of the AI Sandbox series. &lt;a href="https://dev.to/yujisuzuki/your-ai-assistant-can-see-your-secrets-heres-how-i-fixed-it-19lj"&gt;Part 1: Secrets&lt;/a&gt; | &lt;a href="https://dev.to/yujisuzuki/i-gave-my-ai-a-toolbox-it-surprised-me-by-using-it-4on2"&gt;Part 2: Tools&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>dock</category>
      <category>security</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Gave My AI a Toolbox — It Surprised Me by Using It</title>
      <dc:creator>Yuji Suzuki</dc:creator>
      <pubDate>Sat, 14 Feb 2026 07:41:31 +0000</pubDate>
      <link>https://dev.to/yujisuzuki/i-gave-my-ai-a-toolbox-it-surprised-me-by-using-it-4on2</link>
      <guid>https://dev.to/yujisuzuki/i-gave-my-ai-a-toolbox-it-surprised-me-by-using-it-4on2</guid>
      <description>&lt;p&gt;A 3.5MB Go binary was sitting in my source tree, staged for commit. &lt;code&gt;git log&lt;/code&gt; showed nothing — it had never been committed. I had no idea how it got there.&lt;/p&gt;

&lt;p&gt;I asked Claude Code to investigate. I didn't point it to any specific tool. I didn't tell it how to search. I just said: &lt;em&gt;"There's a mystery binary in the repo. Where did it come from?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It solved the mystery in under a minute — using a tool I'd forgotten I built.&lt;/p&gt;

&lt;p&gt;But that's getting ahead of the story.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is Part 3 of the AI Sandbox series. &lt;a href="https://dev.to/yujisuzuki/your-ai-assistant-can-see-your-secrets-heres-how-i-fixed-it-19lj"&gt;Part 1&lt;/a&gt; introduced the AI Sandbox and secret hiding. &lt;a href="https://dev.to/yujisuzuki/official-ai-sandboxes-arrived-why-i-published-mine-anyway-50n7"&gt;Part 2&lt;/a&gt; positioned it against official Docker and Claude Code sandboxes. This article focuses on what happens &lt;em&gt;inside&lt;/em&gt; the sandbox — specifically, what AI does when you give it the ability to discover tools on its own.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Drop a File, Get a Tool
&lt;/h2&gt;

&lt;p&gt;Inside the &lt;a href="https://github.com/YujiSuzuki/ai-sandbox-dkmcp" rel="noopener noreferrer"&gt;AI Sandbox&lt;/a&gt; — a Docker-based environment where AI coding agents run in isolation — I wanted a simple way to extend what AI can do. Not by editing config files or registering MCP servers for every new capability, but something closer to a plugin folder: &lt;strong&gt;drop a file in, and AI can use it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's what &lt;strong&gt;SandboxMCP&lt;/strong&gt; does. It's an MCP server that runs inside the container alongside Claude Code (or Gemini CLI), scanning two directories on demand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.sandbox/tools/&lt;/code&gt; — Go source files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.sandbox/scripts/&lt;/code&gt; — Shell scripts (which can call Python, Node.js, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When AI asks "what tools are available?", SandboxMCP scans these directories, parses the header comments for descriptions and usage info, and exposes them as MCP tools. No build step, no npm install, no manual registration.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;Each file just needs a &lt;a href="https://github.com/YujiSuzuki/ai-sandbox-dkmcp/blob/main/docs/architecture.md#adding-custom-tools" rel="noopener noreferrer"&gt;header comment&lt;/a&gt; describing what it does. SandboxMCP parses these on demand and exposes them as MCP tools. AI discovers a tool through &lt;code&gt;list_tools&lt;/code&gt;, reads its documentation with &lt;code&gt;get_tool_info&lt;/code&gt;, and executes it with &lt;code&gt;run_tool&lt;/code&gt; — all without you telling it to.&lt;/p&gt;

&lt;p&gt;Here's the header from &lt;code&gt;search-history.go&lt;/code&gt; — the tool that ended up solving the mystery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// search-history.go - Claude Code conversation history search tool&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;// Usage:&lt;/span&gt;
&lt;span class="c"&gt;//   go run .sandbox/tools/search-history.go [options] &amp;lt;pattern&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;// Examples:&lt;/span&gt;
&lt;span class="c"&gt;//   go run .sandbox/tools/search-history.go "DockMCP"&lt;/span&gt;
&lt;span class="c"&gt;//   go run .sandbox/tools/search-history.go -role tool -tool Bash "go build"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few lines of comments. That's all AI needs to decide whether a tool is relevant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────────────────────────────┐
│ AI Sandbox (inside container)                      │
│                                                    │
│  ┌─────────────────┐      ┌─────────────────────┐  │
│  │ Claude Code     │ ←──→ │ SandboxMCP (stdio)  │  │
│  │                 │      │                     │  │
│  └─────────────────┘      │ • list_tools        │  │
│                           │ • get_tool_info     │  │
│  ┌─────────────────────┐  │ • run_tool          │  │
│  │ .sandbox/tools/     │  │ • list_scripts      │  │
│  │ • search-history.go │←─│ • get_script_info   │  │
│  │ • usage-report.go   │  │ • run_script        │  │
│  └─────────────────────┘  └─────────────────────┘  │
│  ┌─────────────────────┐                           │
│  │ .sandbox/scripts/   │                           │
│  │ • validate-secrets  │                           │
│  │ • sync-secrets      │                           │
│  └─────────────────────┘                           │
└────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Back to the Mystery Binary
&lt;/h2&gt;

&lt;p&gt;So — a 3.5MB Go binary, staged but never committed. Where did it come from?&lt;/p&gt;

&lt;p&gt;Claude Code started with the obvious: &lt;code&gt;git log&lt;/code&gt;, file timestamps, &lt;code&gt;git diff --cached&lt;/code&gt;. Dead ends. The binary was there, but nothing in the commit history explained it.&lt;/p&gt;

&lt;p&gt;Then something unexpected showed up in the tool calls. Instead of asking me for more context, Claude Code called &lt;code&gt;list_tools&lt;/code&gt; on SandboxMCP — browsing the tool catalog on its own initiative. It found &lt;code&gt;search-history&lt;/code&gt;, read the documentation with &lt;code&gt;get_tool_info&lt;/code&gt;, and decided the &lt;code&gt;-role tool -tool Bash&lt;/code&gt; filter was what it needed. It ran the search across all past Claude Code sessions — not looking for conversations, but for &lt;em&gt;Bash commands&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Within seconds, the culprit appeared: a session from a few days earlier where AI had run &lt;code&gt;go build&lt;/code&gt; without the &lt;code&gt;-o&lt;/code&gt; flag to verify that the code compiled. The build succeeded, but &lt;code&gt;go build&lt;/code&gt; without &lt;code&gt;-o&lt;/code&gt; drops the binary in the current directory. That's how a 3.5MB executable ended up in the source tree.&lt;/p&gt;

&lt;p&gt;I didn't build &lt;code&gt;search-history&lt;/code&gt; for this scenario. I wrote it for finding past conversations about specific topics. But because it was sitting in &lt;code&gt;.sandbox/tools/&lt;/code&gt;, SandboxMCP exposed it, and Claude Code decided — on its own — that it was the right tool for the job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The auto-discovery mechanism turned a tool I'd forgotten about into the solution for a problem I hadn't anticipated.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovery vs. Installation
&lt;/h2&gt;

&lt;p&gt;By now, AI using tools is nothing remarkable. What caught my attention was the &lt;em&gt;how&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There are already several MCP servers for searching Claude Code conversation history — &lt;a href="https://github.com/Vvkmnn/claude-historian-mcp" rel="noopener noreferrer"&gt;claude-historian-mcp&lt;/a&gt;, &lt;a href="https://github.com/TonySimonovsky/claude-code-conversation-search-mcp" rel="noopener noreferrer"&gt;claude-code-conversation-search-mcp&lt;/a&gt;, and others. They work well. If I'd installed one, Claude Code could have searched past sessions too.&lt;/p&gt;

&lt;p&gt;But here's the thing: &lt;strong&gt;I would never have installed a conversation-search MCP server to debug a mystery binary.&lt;/strong&gt; That connection — "unknown file in the repo" → "search past AI sessions for Bash commands" — only became obvious &lt;em&gt;after&lt;/em&gt; the answer was found. Before that, it was a lateral leap that required recognizing a tool built for one purpose could solve a completely different problem.&lt;/p&gt;

&lt;p&gt;That's the gap between installation and discovery. When you install a tool, it exists because you anticipated the need. When AI discovers tools from a catalog, it can make connections you didn't plan for — repurposing tools across problem boundaries you never drew.&lt;/p&gt;

&lt;p&gt;You don't have to predict every need upfront. You build a toolbox, and AI reaches for the right tool when the moment comes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Your Own Toolbox
&lt;/h2&gt;

&lt;p&gt;The pattern scales with the tools you add. Shell scripts can call Python, Node.js, or anything else installed in the container. The only requirement is a header comment that describes what the tool does.&lt;/p&gt;

&lt;p&gt;Some examples from this project:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;th&gt;How AI Uses It&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search-history.go&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Search past Claude Code sessions&lt;/td&gt;
&lt;td&gt;"What did we work on last week?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;usage-report.go&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Token usage by model and period&lt;/td&gt;
&lt;td&gt;"How much did I spend this month?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validate-secrets.sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Verify secret hiding works&lt;/td&gt;
&lt;td&gt;"Are my secrets properly hidden?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sync-secrets.sh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sync secret config across environments&lt;/td&gt;
&lt;td&gt;"Check if my secret config is consistent"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can start with one tool. The cost of an unused tool sitting in a directory is zero. The value of having the right tool already there when an unexpected problem arises — that's what this article is about.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Doesn't Solve
&lt;/h2&gt;

&lt;p&gt;To be consistent with the honesty in &lt;a href="https://dev.to/yujisuzuki/your-ai-assistant-can-see-your-secrets-heres-how-i-fixed-it-19lj"&gt;Part 1&lt;/a&gt; and &lt;a href="https://dev.to/yujisuzuki/official-ai-sandboxes-arrived-why-i-published-mine-anyway-50n7"&gt;Part 2&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools must already exist.&lt;/strong&gt; AI discovers tools — it doesn't create them from scratch in the moment. Someone has to write the tool and place it in the directory first. (Though in practice, AI can write a tool in one session that another session later discovers and uses.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discovery depends on good descriptions.&lt;/strong&gt; If your header comment is vague, AI may not recognize the tool as relevant. The quality of the metadata matters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scoped to the sandbox.&lt;/strong&gt; SandboxMCP only sees tools inside the container. It doesn't discover tools on the host OS or in other containers — that's &lt;a href="https://dev.to/yujisuzuki/your-ai-assistant-can-see-your-secrets-heres-how-i-fixed-it-19lj"&gt;DockMCP's&lt;/a&gt; job.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No sandboxing within the sandbox.&lt;/strong&gt; Tools run with the same permissions as AI itself. SandboxMCP doesn't add an extra isolation layer for tool execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Fits Together
&lt;/h2&gt;

&lt;p&gt;SandboxMCP completes the tooling stack of the &lt;a href="https://github.com/YujiSuzuki/ai-sandbox-dkmcp" rel="noopener noreferrer"&gt;AI Sandbox&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Location&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AI Sandbox&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Container&lt;/td&gt;
&lt;td&gt;Secure environment where AI runs. Secrets hidden via volume mounts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SandboxMCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Container (stdio)&lt;/td&gt;
&lt;td&gt;Tool auto-discovery and execution inside the sandbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DockMCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Host OS (SSE)&lt;/td&gt;
&lt;td&gt;Cross-container access — AI can check logs and run tests in other containers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;SandboxMCP auto-registers on container startup. No manual setup required.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;VS Code + DevContainer:&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;git clone https://github.com/YujiSuzuki/ai-sandbox-dkmcp.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ai-sandbox-dkmcp
code &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# Cmd+Shift+P → "Dev Containers: Reopen in Container"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CLI (no VS Code needed):&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;git clone https://github.com/YujiSuzuki/ai-sandbox-dkmcp.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ai-sandbox-dkmcp
./cli_sandbox/claude.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once inside, try dropping your own tool in &lt;code&gt;.sandbox/tools/&lt;/code&gt; and asking AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"What tools are available?"&lt;/li&gt;
&lt;li&gt;"What did we work on this week?"&lt;/li&gt;
&lt;li&gt;"Show me token usage this month"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't have to tell AI which tool to use. It figures that out on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Took Away
&lt;/h2&gt;

&lt;p&gt;The binary mystery was a small thing. But it changed how I think about AI tooling.&lt;/p&gt;

&lt;p&gt;I'm not claiming drop-in tools replace dedicated MCP servers — those are more capable and better integrated for specific use cases. But for the long tail of small, project-specific utilities that don't justify their own server, a plugin folder works remarkably well. The cost of an unused tool sitting in a directory is zero.&lt;/p&gt;

&lt;p&gt;I built a search tool to find old conversations. AI used it to track down a mystery I didn't know I had. That's what happens when you stop installing tools for specific problems and start building a toolbox.&lt;/p&gt;




&lt;h2&gt;
  
  
  Appendix: The Actual Conversation
&lt;/h2&gt;

&lt;p&gt;Everything above describes what happened. Here's how it actually looked — the unedited exchange between me and Claude Code that inspired this article.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This conversation was originally in Japanese. The following is a translated version.&lt;br&gt;
Original: &lt;a href="https://zenn.dev/yujisuzuki/articles/9728a8a3f7905a#%E3%81%8A%E3%81%BE%E3%81%91-%EF%BC%88%E3%81%9D%E3%81%AE%E6%99%82%E3%81%AE%E3%83%AA%E3%82%A2%E3%83%AB%E3%81%AAai%E3%81%A8%E3%81%AE%E4%BC%9A%E8%A9%B1%EF%BC%89" rel="noopener noreferrer"&gt;Zenn article (Japanese)&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;● ---
  Code Review Results

  Project: /workspace
  Mode: Git mode (staged changes)
  Review target: Staged changes (12 files, +1264 -46)
  Summary: Addition of usage-report.go, improvements to search-history.go
  (date filters, timezone support), toolparser separator support,
  documentation updates

  Issues Found

  Issue 1: Compiled binary is staged
  - File: .sandbox/sandbox-mcp/search-history
  - Line: N/A (binary, 3.5MB)
  - Basis: Best practice violation
  - Confidence: 85/100

  Binary files /dev/null and b/.sandbox/sandbox-mcp/search-history differ

  Go projects should not commit compiled binaries. It can be regenerated
  with make install, bloats the repository, and causes platform-dependent
  issues.

❯ new file:   .sandbox/sandbox-mcp/search-history
  This one?

● Yes, that's the one. .sandbox/sandbox-mcp/search-history is a compiled
  Go binary (3.5MB) included in staging.

  Since it can be regenerated with make install or go build, there's no
  need to commit it. To unstage:

  git reset HEAD .sandbox/sandbox-mcp/search-history

  You may also want to add it to .gitignore.

❯ When did I build this binary?

● Read 2 files (ctrl+o to expand)

● Bash(git log --all --diff-filter=A -- .sandbox/sandbox-mcp/search-history)
  ⎿  (No content)

● Found the cause in past conversations.

  In session 16f4a485-b7d (today, 18:53), the AI ran
  go build /workspace/.sandbox/tools/search-history.go to verify
  compilation — but without the -o flag, so the binary was written to
  the current directory (.sandbox/sandbox-mcp/).

  In another session (e33d09a7), it correctly used go build -o /dev/null,
  but session 16f4a485 forgot the -o flag, leaving the binary behind.

  It wasn't intentional — safe to unstage.

❯ Wait... you searched past conversation history? With search-history?

● Yes, exactly. Here's what I ran via SandboxMCP's run_tool:

  search-history.go -role tool -tool Bash -after 2026-02-09 "search-history" -context 100

  I filtered Bash tool executions containing "search-history" from today's
  sessions to pinpoint when and how go build was run.

  Review flagged the issue → investigation completed with its own tools.
  That's the beauty of .sandbox/tools/.

❯ That's incredible. Without the search, we'd never have known the cause, right?

● Exactly. Without search-history, "why is this binary here?" would have
  remained unanswered:

  - git log had nothing — the file was never committed
  - The file timestamp (18:53) tells you *when*, not *what happened*
  - The previous session's AI is gone

  The conversation history was the only record of "go build was run
  without -o", and search-history is what pulled that out.

  AI sessions are ephemeral. Without a way to search past sessions,
  questions like "who created this and when?" become unanswerable.
  It's unglamorous, but genuinely useful.

❯ This is amazing — can we write about this somehow?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last question led to this article.&lt;/p&gt;

&lt;p&gt;The part I find most interesting isn't that the AI solved the problem. It's that &lt;code&gt;git log&lt;/code&gt; returned nothing, and instead of asking me for more context, it reached for a tool I'd forgotten was there — and used it in a way I hadn't anticipated when I wrote it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is Part 3 of the AI Sandbox series. &lt;a href="https://dev.to/yujisuzuki/your-ai-assistant-can-see-your-secrets-heres-how-i-fixed-it-19lj"&gt;Part 1: Your AI Assistant Can See Your Secrets — Here's How I Fixed It&lt;/a&gt; / &lt;a href="https://dev.to/yujisuzuki/official-ai-sandboxes-arrived-why-i-published-mine-anyway-50n7"&gt;Part 2: Official AI Sandboxes Arrived — Why I Published Mine Anyway&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/YujiSuzuki/ai-sandbox-dkmcp" rel="noopener noreferrer"&gt;AI Sandbox + DockMCP&lt;/a&gt; is open source (MIT License). Feedback and contributions welcome.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>docker</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Your AI Assistant Can See Your Secrets — Here's How I Fixed It</title>
      <dc:creator>Yuji Suzuki</dc:creator>
      <pubDate>Tue, 03 Feb 2026 14:58:07 +0000</pubDate>
      <link>https://dev.to/yujisuzuki/your-ai-assistant-can-see-your-secrets-heres-how-i-fixed-it-19lj</link>
      <guid>https://dev.to/yujisuzuki/your-ai-assistant-can-see-your-secrets-heres-how-i-fixed-it-19lj</guid>
      <description>&lt;p&gt;AI coding agents are incredible. They refactor code, write tests, debug across files. But there's a problem nobody talks about enough: &lt;strong&gt;they read everything in your project directory&lt;/strong&gt;, including your &lt;code&gt;.env&lt;/code&gt; files, API keys, and private certificates.&lt;/p&gt;

&lt;p&gt;I found out the hard way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Incident
&lt;/h2&gt;

&lt;p&gt;I was using Claude Code to investigate an issue that spanned both a server-side project and an iOS app. The server repo was my working directory, but the iOS source lived in a sibling directory. I asked Claude Code if it could see the iOS code too. It said yes — so I let it investigate.&lt;/p&gt;

&lt;p&gt;What I didn't realize: the iOS project had its own &lt;code&gt;.claude/settings.json&lt;/code&gt; with deny rules to protect API keys. But Claude Code only reads the settings from the directory it was launched in. The iOS project's deny rules were ignored. The AI read the API keys.&lt;/p&gt;

&lt;p&gt;Fortunately, they were ad network keys — not catastrophic. But the experience stuck with me. I had configured the protection correctly, and it still didn't work because of a scoping limitation I didn't know about.&lt;/p&gt;

&lt;p&gt;And the data backs this up. GitHub reported &lt;a href="https://www.darkreading.com/application-security/coders-adopt-ai-agents-security-pitfalls-lurk-2026" rel="noopener noreferrer"&gt;39 million leaked secrets&lt;/a&gt; in repositories in 2024 alone. With 82% of developers now using AI tools, the attack surface is only growing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Is Getting Worse, Not Better
&lt;/h2&gt;

&lt;p&gt;2025 brought a wave of new attack vectors targeting AI coding tools specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PromptPwnd&lt;/strong&gt; — Attackers inject malicious instructions into PR descriptions and commit messages. When an AI agent processes these in CI/CD, it leaks secrets or modifies workflows. &lt;a href="https://www.darkreading.com/application-security/coders-adopt-ai-agents-security-pitfalls-lurk-2026" rel="noopener noreferrer"&gt;At least five Fortune 500 companies were affected&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IDEsaster&lt;/strong&gt; — Prompt injection through legitimate IDE features. CVEs were issued for &lt;a href="https://www.pillar.security/blog/new-vulnerability-in-github-copilot-and-cursor-how-hackers-can-weaponize-code-agents" rel="noopener noreferrer"&gt;Cursor, Roo Code, JetBrains Junie, GitHub Copilot, and Claude Code&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rules File Backdoor&lt;/strong&gt; — Hidden Unicode characters in configuration files silently instruct AI to insert malicious code. Virtually invisible to developers during code review.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't theoretical. They're happening now.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Existing Solutions Do — and Don't Do
&lt;/h2&gt;

&lt;p&gt;The industry is responding, and there are real options available now:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://code.claude.com/docs/en/sandboxing" rel="noopener noreferrer"&gt;Claude Code Sandboxing&lt;/a&gt;&lt;/strong&gt; uses OS-level primitives (Seatbelt on macOS, bubblewrap on Linux) to restrict filesystem writes and network access. You can also add &lt;code&gt;Read&lt;/code&gt; deny rules in permissions to block AI from reading specific files. This is solid for preventing command execution attacks and prompt injection damage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://docs.docker.com/ai/sandboxes" rel="noopener noreferrer"&gt;Docker AI Sandboxes&lt;/a&gt;&lt;/strong&gt; run AI agents in isolated microVMs with their own Docker daemon. The agent can't touch your host system. Great for giving agents full autonomy without risking your machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.docker.com/blog/mcp-toolkit-mcp-servers-that-just-work/" rel="noopener noreferrer"&gt;Docker MCP Toolkit&lt;/a&gt;&lt;/strong&gt; provides 200+ containerized MCP servers with built-in isolation and secret management.&lt;/p&gt;

&lt;p&gt;These are good tools. But there are two gaps they don't fully address:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gap 1: Filesystem-level secret hiding.&lt;/strong&gt; Claude Code's deny rules are application-level — they depend on correct configuration and the AI tool respecting them. There are also scope limitations: deny rules &lt;a href="https://github.com/anthropics/claude-code/issues/12962" rel="noopener noreferrer"&gt;don't traverse parent directories&lt;/a&gt;, so in a monorepo or multi-project workspace, settings in one project won't protect secrets in a sibling project. Docker AI Sandboxes sync your entire workspace directory into the microVM with no mechanism to exclude specific files. In both cases, a &lt;code&gt;.env&lt;/code&gt; file sitting in your project directory is either visible or requires careful per-tool configuration to hide.&lt;/p&gt;

&lt;p&gt;What if the secrets simply didn't exist in AI's filesystem? Not blocked by a rule, not filtered by a config — just not there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gap 2: Cross-container debugging.&lt;/strong&gt; Docker AI Sandboxes are fully isolated — each sandbox can't communicate with others. Claude Code's sandbox restricts outbound access. But in a real microservice setup, AI needs to check API logs, run tests in other containers, and inspect services to be useful. How do you give it that access safely?&lt;/p&gt;

&lt;h2&gt;
  
  
  My Solution: AI Sandbox + DockMCP
&lt;/h2&gt;

&lt;p&gt;The existing tools above are valuable — and you should use them. Claude Code's sandboxing reduces permission fatigue. Docker AI Sandboxes provide strong isolation for autonomous agents.&lt;/p&gt;

&lt;p&gt;But I needed something that works at a different layer: &lt;strong&gt;making secrets physically absent from AI's filesystem&lt;/strong&gt;, while still giving AI &lt;strong&gt;controlled access to other containers&lt;/strong&gt; for debugging.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://github.com/YujiSuzuki/ai-sandbox-dkmcp" rel="noopener noreferrer"&gt;AI Sandbox&lt;/a&gt; — a Docker-based development environment that fills these two gaps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Secret hiding&lt;/strong&gt;: Specific files don't exist in AI's filesystem — not blocked, not filtered, just absent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-container access&lt;/strong&gt;: AI can check logs and run tests in other containers through a controlled gateway&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's complementary to existing tools. You can use Claude Code's sandbox &lt;em&gt;inside&lt;/em&gt; the AI Sandbox for defense in depth.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Secret Hiding Works
&lt;/h3&gt;

&lt;p&gt;The trick is surprisingly simple: Docker volume mounts.&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;# docker-compose.yml&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# AI sees an empty file instead of real .env&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/dev/null:/workspace/my-app/.env:ro&lt;/span&gt;

&lt;span class="na"&gt;tmpfs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# AI sees an empty directory instead of real secrets&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/workspace/my-app/secrets:ro&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When AI runs inside the container, it literally cannot see the real files. They don't exist in its filesystem. But other containers — the ones actually running your app — mount the real files normally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Sandbox (where AI runs)
├── my-app/
│   ├── src/           ← AI can read and edit all code
│   ├── .env           ← Empty (mounted from /dev/null)
│   └── secrets/       ← Empty directory (tmpfs)

API Container (where your app runs)
├── my-app/
│   ├── src/           ← Same code
│   ├── .env           ← Real secrets
│   └── secrets/       ← Real private keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No runtime agents scanning for secrets. No AI configuration that could be bypassed. The secrets simply don't exist in AI's world.&lt;/p&gt;

&lt;p&gt;The risk with this approach is forgetting to hide a file. To catch that, the sandbox runs startup validation that automatically checks whether your AI tool's deny rules (e.g., &lt;code&gt;.claude/settings.json&lt;/code&gt;) and your &lt;code&gt;docker-compose.yml&lt;/code&gt; volume mounts are in sync. If a secret file is blocked in one but not the other, you get a warning on startup — before AI ever sees it.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Cross-Container Access Works
&lt;/h3&gt;

&lt;p&gt;Hiding secrets creates a new problem: AI can't access other containers for debugging. That's where DockMCP comes in.&lt;/p&gt;

&lt;p&gt;DockMCP is an MCP (Model Context Protocol) server that runs on the host OS and acts as a controlled gateway between the AI sandbox and other Docker containers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Sandbox  →  DockMCP (host)  →  API Container
  "show me       checks            returns last
   the logs"     security policy   100 log lines
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AI can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read logs from any allowed container&lt;/li&gt;
&lt;li&gt;Run whitelisted commands (like &lt;code&gt;npm test&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Check resource usage (CPU, memory)&lt;/li&gt;
&lt;li&gt;Inspect container configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI cannot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start or stop containers&lt;/li&gt;
&lt;li&gt;Access files outside allowed paths&lt;/li&gt;
&lt;li&gt;Run arbitrary commands&lt;/li&gt;
&lt;li&gt;Bypass the security policy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The security policy is defined in a simple YAML file:&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;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;moderate"&lt;/span&gt;
  &lt;span class="na"&gt;allowed_containers&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;my-api-*"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-web-*"&lt;/span&gt;
  &lt;span class="na"&gt;exec_whitelist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-api"&lt;/span&gt;&lt;span class="err"&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;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;test"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lint"&lt;/span&gt;
  &lt;span class="na"&gt;blocked_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;/etc/shadow"&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"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DockMCP also automatically masks sensitive data (passwords, API keys, tokens) in log output and command results, so even when AI reads logs from other containers, secrets don't leak through.&lt;/p&gt;

&lt;p&gt;For the full configuration reference, see the &lt;a href="https://github.com/YujiSuzuki/ai-sandbox-dkmcp/blob/main/dkmcp/README.md" rel="noopener noreferrer"&gt;DockMCP documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture Overview
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────┐
│ Host OS                                 │
│                                         │
│  DockMCP Server (:8080)                 │
│    ├── Security policy enforcement      │
│    └── Container access gateway         │
│                                         │
│  Docker Engine                          │
│    ├── AI Sandbox                       │
│    │   ├── Claude Code / Gemini / etc.  │
│    │   └── secrets → hidden             │
│    │                                    │
│    ├── API Container                    │
│    │   └── secrets → real files         │
│    │                                    │
│    └── Web Container                    │
└─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What This Looks Like in Practice
&lt;/h2&gt;

&lt;p&gt;Here's a real debugging session. I ask AI to help investigate a failing API endpoint:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; The &lt;code&gt;/api/notes&lt;/code&gt; endpoint returns 500. Can you check the API logs?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI uses DockMCP to fetch logs from the API container:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI:&lt;/strong&gt; I can see the error in the logs. There's a JWT verification failure at line 42 of &lt;code&gt;auth.js&lt;/code&gt;. The token format changed after a recent update. Let me check the code...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI reads the auth middleware code (visible in the sandbox), identifies the bug, and proposes a fix. It never sees the JWT secret key (hidden via volume mount), but it doesn't need to — it can see the code and the error logs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt; Looks good. Run the tests to make sure it passes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;AI runs &lt;code&gt;npm test&lt;/code&gt; via DockMCP in the API container and confirms all tests pass.&lt;/p&gt;

&lt;p&gt;The AI had everything it needed to debug and fix the issue, without ever accessing a single secret.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Try It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Minimal Setup (Sandbox Only)
&lt;/h3&gt;

&lt;p&gt;If you just want secret hiding without cross-container access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/YujiSuzuki/ai-sandbox-dkmcp.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ai-sandbox-dkmcp
code &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# Cmd+Shift+P → "Dev Containers: Reopen in Container"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit &lt;code&gt;docker-compose.yml&lt;/code&gt; to hide your secret files, and you're done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Full Setup (Sandbox + DockMCP)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Clone and enter&lt;/span&gt;
git clone https://github.com/YujiSuzuki/ai-sandbox-dkmcp.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ai-sandbox-dkmcp

&lt;span class="c"&gt;# 2. Start DockMCP on host OS&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;dkmcp
make &lt;span class="nb"&gt;install
&lt;/span&gt;dkmcp serve &lt;span class="nt"&gt;--config&lt;/span&gt; configs/dkmcp.example.yaml

&lt;span class="c"&gt;# 3. Open DevContainer in VS Code&lt;/span&gt;
code &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="c"&gt;# Cmd+Shift+P → "Dev Containers: Reopen in Container"&lt;/span&gt;
&lt;span class="c"&gt;# Or use the CLI sandbox (no VS Code needed):&lt;/span&gt;
&lt;span class="c"&gt;# ./cli_sandbox/claude.sh or ./cli_sandbox/gemini.sh&lt;/span&gt;

&lt;span class="c"&gt;# 4. Register DockMCP as an MCP server (inside the container)&lt;/span&gt;
claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; sse &lt;span class="nt"&gt;--scope&lt;/span&gt; user dkmcp http://host.docker.internal:8080/sse
&lt;span class="c"&gt;# Or for Gemini CLI:&lt;/span&gt;
gemini mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; sse dkmcp http://host.docker.internal:8080/sse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo includes a demo application (SecureNote) so you can see the full flow in action. For detailed setup instructions, troubleshooting, and connection verification, see the &lt;a href="https://github.com/YujiSuzuki/ai-sandbox-dkmcp" rel="noopener noreferrer"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest Limitations
&lt;/h2&gt;

&lt;p&gt;I want to be upfront about what this does and doesn't do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local development only.&lt;/strong&gt; DockMCP has no authentication yet, so it's designed for local use only. I'd like to add authentication in the future, but no timeline has been set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No network restriction by default.&lt;/strong&gt; AI can still make outbound HTTP requests. You can add network restrictions using &lt;a href="https://github.com/anthropics/claude-code/blob/main/.devcontainer/init-firewall.sh" rel="noopener noreferrer"&gt;Anthropic's official firewall script&lt;/a&gt; or Docker network policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker required.&lt;/strong&gt; The volume mount approach means you need a Docker-compatible runtime. No Docker, no secret hiding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only tested on macOS.&lt;/strong&gt; It should work on Linux and Windows, but I haven't verified it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a replacement for proper secrets management.&lt;/strong&gt; This is a development-time protection layer. Use HashiCorp Vault, AWS Secrets Manager, etc. for production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complementary, not competing.&lt;/strong&gt; This works alongside Claude Code's sandbox and Docker AI Sandboxes. Use them together for defense in depth.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;85% of developers now use AI coding tools (&lt;a href="https://www.javacodegeeks.com/2025/12/ai-assisted-coding-in-2026-how-github-copilot-cursor-and-amazon-q-are-reshaping-developer-workflows.html" rel="noopener noreferrer"&gt;JetBrains, 2025&lt;/a&gt;). AI writes &lt;a href="https://dev.to/alexmercedcoder/ai-coding-dominates-2026-week-of-january-20-27-7lc"&gt;29% of new code&lt;/a&gt; in the US. These tools aren't going away — they're becoming the default way we write software.&lt;/p&gt;

&lt;p&gt;But the security model hasn't caught up. We give AI full read access to our projects and hope for the best. When something leaks, we rotate keys and move on.&lt;/p&gt;

&lt;p&gt;We can do better. The approach doesn't have to be complicated:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Isolate AI in a container&lt;/strong&gt; so secrets can be hidden at the filesystem level&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provide controlled access&lt;/strong&gt; to other containers for debugging&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Define explicit security policies&lt;/strong&gt; for what AI can and cannot do&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;a href="https://github.com/YujiSuzuki/ai-sandbox-dkmcp" rel="noopener noreferrer"&gt;AI Sandbox + DockMCP&lt;/a&gt; template is one implementation of this idea. Hit "Use this template" on GitHub to start your own.&lt;/p&gt;

&lt;p&gt;The goal isn't to restrict AI — it's to let AI work freely in a space where secrets simply don't exist.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;AI Sandbox + DockMCP is open source (MIT License). Contributions and feedback are welcome on &lt;a href="https://github.com/YujiSuzuki/ai-sandbox-dkmcp" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>security</category>
      <category>ai</category>
      <category>docker</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
