> ## Content Index
> Fetch the complete content index at: https://broskietech.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Building a Docker Sandbox for AI Coding Agents
- URL: https://broskietech.com/building-a-docker-sandbox-for-ai-coding-agents/
- Published: 2026-10-23T02:41:44.000Z
- Updated: 2026-10-23T03:03:03.000Z
- Author: Brett Pelkey
- Tags: Developer Tools

AI coding agents have become incredibly useful for software development. Tools like Claude Code, Codex, and OpenCode can explore repositories, write code, run commands, and help troubleshoot problems with surprisingly little intervention.

However, there's one thing that has always bothered me about giving an AI agent access to my development environment: **how much access does it actually need?**

Like many developers, I have a collection of personal projects, Docker configurations, Kubernetes manifests, and scripts sitting on my machine. Some of these repositories contain configuration files, environment variables, and other information that I wouldn't want an AI agent accidentally reading, modifying, or exposing.

While these agents generally do a good job of following instructions, I didn't want to rely entirely on prompts telling them what they could and couldn't access.

Instead, I wanted to enforce those boundaries at the environment level.

That's what led me to build **Safe-Agent**, a lightweight Docker-based sandbox for running AI coding agents in an isolated development environment.

## What I Wanted To Accomplish

My goal wasn't to build an elaborate security platform. I wanted something relatively simple that I could use with my existing development workflow.

There were a few things I wanted to achieve:

- **Filesystem isolation:** Agents should only have access to the repositories and directories I explicitly provide.
- **Protect sensitive files:** Credentials, `.env` files, SSH keys, and other sensitive information shouldn't be available inside the container.
- **Support multiple agents:** I wanted to use Claude Code, Codex, or OpenCode without maintaining separate environments for each.
- **Maintain development tools:** The container should still have access to the tools needed for everyday development, including Git and other CLI utilities.
- **Persistent agent configuration:** Authentication, settings, and conversation history should survive container restarts.
- **Simple workflow:** Starting an agent, making changes, and bringing those changes back into my actual repositories should be straightforward.

Most importantly, I wanted to maintain control over what changes were eventually applied to my real working environment.

## The Basic Idea

The approach is fairly straightforward.

Rather than launching an AI agent directly on my host machine, I launch it inside a Docker container with access to a dedicated workspace.

My actual repositories stay outside the container. I copy the files I want the agent to work on into that workspace, let the agent make its changes, and then review those changes before copying anything back.

This gives me an additional layer of separation between the AI agent and the rest of my development environment.

It also means I can experiment with different agents without worrying as much about one of them accidentally modifying unrelated projects.

Of course, **Docker is not a perfect security boundary**, and container isolation alone doesn't eliminate every risk. But with carefully configured mounts, permissions, and network access, it provides a useful additional layer of protection for my workflow.

## How Safe-Agent Works

Safe-Agent is built around a few simple shell scripts and a Docker container.

The workflow looks something like this:

1. Clone a repository into the safe-agent work directory using `git clone`.
2. Then pull changes from a repository into the sandbox using `agent-pull`.
3. Start the container with the AI coding agent of my choice using `agent-start`.
4. Let the agent inspect, modify, and test the code inside the isolated workspace.
5. Review the changes before bringing them back to the original repository using `agent-push`.

This keeps the workflow familiar while reducing the amount of access an agent has to my host system.

In the sections below, I'll walk through how I configured the Docker environment, handled persistent agent settings, integrated it with my existing development tools, and worked through a few challenges along the way.

## Building the Docker Container

With the basic workflow figured out, the next step was building a Docker container that could run the AI coding agents while keeping them separated from my host environment.

I wanted to keep the setup relatively lightweight. The container didn't need to replicate my entire development machine; it just needed the tools required to work with my projects.

I used the official **Node.js 22 image based on Debian Bookworm** as the starting point. From there, I installed a few common development utilities, including Git, Bash, curl, and build tools. I also added `uv` for managing Python environments and dependencies without needing a full Python installation in the base image.

Next, I installed the three AI coding agents I planned to use: **Claude Code, Codex, and OpenCode**. Since all three can be installed through npm, I could include them in the same Docker image rather than maintaining separate containers for each agent.

Finally, I set `/workspace` as the working directory, which is where the project files would be mounted when starting the container.

This gave me a relatively simple environment where I could switch between coding agents depending on the task, while keeping their execution inside the container.

### Isolating the Workspace

The most important part of the setup was controlling what directories the container could access.

Instead of mounting my entire home directory or Git directory, I only mount the dedicated Safe-Agent workspace into the container.

For example, my local directory structure looks something like this:

```text
~/git/
├── project/                  # Original repository
└── safe-agent/
    ├── work/
    │   └── project/          # AI agent's working copy
    ├── container/
    └── bin/
```

With this setup, the AI agent can work within the mounted workspace, but it doesn't have direct access to my original repository or other directories on my machine.

This is particularly useful when working with projects that contain sensitive configuration files. I can control what gets copied into the workspace rather than exposing everything on my host.

Of course, volume mounts are only one part of container security. A container can still have network access, and files inside the workspace may contain sensitive information. It's important to consider those risks separately.

### Keeping Agent Settings Persistent

One challenge I encountered was maintaining agent configuration between container runs.

I didn't want to authenticate with each coding agent every time I started a new container, and I wanted conversation history and configuration to remain available.

To solve this, I added persistent mounts for the agents' configuration and data directories.

This allows me to stop and recreate the container without losing the agent's settings or previous sessions.

It also means I can switch between different agents while continuing to use the same isolated workspace.

### Starting an Agent

To make the process easier, I created a few shell scripts to handle launching the container and selecting an agent.

For example, from inside a project in the Safe-Agent workspace, I can run:

```bash
agent-start codex
```

Or switch to another agent:

```bash
agent-start claude
```

## Managing Repositories

With the container working, the next challenge was figuring out how to manage the files the agents would modify.

I wanted the agent to work on a separate copy of my repository, while keeping my original local repository untouched until I had reviewed the changes.

For each project, I first clone the Git repository into Safe-Agent's `work` directory.

For example, I might already have a project located at:

```text
~/git/project
```

I then clone that same repository into the Safe-Agent workspace:

```bash
cd ~/git/safe-agent/work
git clone <repository-url> project
```

This gives me two independent working copies of the same repository.

One is my original development repository, while the other is dedicated to AI-assisted development.

One benefit of using `git clone` rather than copying my existing project directory is that it only checks out files tracked by Git. This means local files that aren't committed, such as ignored `.env` files, credentials, and temporary files, won't automatically end up in the Safe-Agent workspace.

This provides an additional layer of protection, although it's still important to ensure sensitive files haven't accidentally been committed to the repository. 

You can also `git clone` from a local path instead of the remote URL, which is my preferred method. 

### Synchronizing Changes

Since I may still make changes to my original repository, I wanted an easy way to keep the Safe-Agent copy up to date.

I created two commands to handle synchronizing changes between the repositories:

- **`agent-pull`** — Pulls changes from my original local repository into the Safe-Agent workspace.
- **`agent-push`** — Transfers changes from the Safe-Agent workspace back to my original local repository.

While these commands use Git under the hood, they operate between two local repositories rather than communicating with a remote Git server.

One advantage of this approach is that Git only transfers committed changes. Untracked files and ignored files, such as local `.env` files, credentials, and other sensitive configurations, aren't automatically transferred into the Safe-Agent workspace.

This gives me another layer of protection while still allowing me to easily synchronize code between my original repository and the isolated environment.

For example, I can navigate to my Safe-Agent project and run:

```bash
cd ~/git/safe-agent/work/project
agent-pull
```

Once everything is synchronized, I can start my preferred coding agent and let it work on the project.

### Reviewing Changes in My IDE

One part of this workflow that I really like is how I use my IDE to review the agent's work.

I have my IDE configured with both the original repository and the Safe-Agent working copy. This makes it easy to switch between them and inspect what the agent has modified without needing to leave my normal development environment.

Since the two repositories are separate, I can inspect the agent's changes, compare files, and review Git diffs before deciding whether to bring anything back to my original repository.

If I'm not satisfied with the changes, I can ask the agent to make further adjustments or discard the work entirely.

Once I'm happy with the results, I run:

```bash
agent-push
```

This transfers the changes back to my original local repository, where I can perform any final checks and commit them to Git.

**The important distinction is that the AI agent doesn't directly modify my original working repository.** I get to decide when its changes are ready to be transferred.

### Why I Prefer This Approach

This workflow introduces a few extra steps compared to running an AI agent directly inside my primary repository, but I think the tradeoff is worthwhile.

I get the convenience of AI-assisted coding while retaining control over which files the agent can access and when its changes are applied to my projects.

It also gives me the flexibility to experiment. I can try a different approach, switch agents, or even start over without worrying about the state of my original development repository.

## Lessons Learned

Building Safe-Agent was a good learning experience, particularly when it came to balancing security with convenience. I wanted an environment that was isolated enough to give me some peace of mind, but not so restrictive that working with AI agents became a hassle.

A few things stood out during development.

### Mounting Directories Requires Some Planning

One issue I encountered early on was how Docker handles mounted directories. My initial setup worked well with a single project, but I ran into problems when trying to work with multiple repositories.

I eventually adjusted the setup to better handle different project directories without interfering with existing workspaces.

It reinforced the importance of being deliberate about which directories are mounted into a container, especially when filesystem isolation is one of the main goals.

### Persistent Configuration Makes a Big Difference

Another challenge was figuring out where each AI coding agent stored its configuration, authentication information, and session history.

Each agent handles this a little differently, so getting persistence working consistently took some experimentation.

Once I configured the appropriate persistent mounts, switching between agents and restarting containers became much more convenient.

### Keeping the Workflow Simple Matters

One thing I didn't want was to spend more time managing the sandbox than actually writing code.

Having a few straightforward commands like `agent-pull`, `agent-start`, and `agent-push` made the environment much easier to use.

I've also found that keeping both repositories accessible in my IDE works well. I can review changes before transferring them back, without needing to give the agent access to my original repository.

Ultimately, the separation between my normal development environment and the AI workspace has been worth the additional setup.

## Limitations and Future Improvements

While Safe-Agent provides an additional layer of isolation, it's important to recognize that it isn't a completely secure or foolproof environment.

### Docker Isn't a Perfect Security Boundary

Containers share the host's kernel, and misconfigured permissions, mounts, or container privileges can undermine their isolation.

Safe-Agent reduces the agent's access to my host filesystem, but that doesn't mean it's immune to every possible security issue.

I still need to be careful about what directories I mount, what permissions the container has, and which tools I allow the agents to execute.

### Network Access Is Another Consideration

Filesystem isolation is only part of the equation. Even if an agent can't directly access sensitive files on the host, it may still be able to communicate with external services.

I've experimented with restricting network access while allowing specific connections needed for development, such as communicating with my Fusion 360 MCP server.

This is an area where I'd like to continue improving the setup, particularly around making network restrictions easier to configure and maintain.

### Git Isolation Has Its Own Limitations

Using separate Git repositories works well for my workflow, but it introduces some additional steps.

I need to make sure changes are committed and synchronized appropriately between the two repositories. Uncommitted changes in my original repository won't automatically make their way into Safe-Agent through normal Git operations.

It's also important to remember that Git isolation doesn't guarantee sensitive files are excluded. A credential that has already been committed to a repository can still be transferred into the sandbox, even if it's later added to `.gitignore`.

### Future Improvements

There are a few areas I'd like to continue exploring, including making it easier to initialize new projects, improving support for multiple simultaneous workspaces, and further refining the container's network permissions.

For now, though, Safe-Agent accomplishes what I originally set out to do: provide a relatively simple way to run AI coding agents without giving them unrestricted access to my development environment.

## Source Code & Getting Started

The complete Safe-Agent project is available on [GitHub](https://github.com/bp974/safe-agent?ref=broskietech.com), including the Docker configuration, helper scripts, and setup instructions.

If you're interested in trying it yourself, you can clone the repository and follow the instructions in the README.

Feel free to explore the code, adapt it to your own workflow, or contribute improvements through GitHub.