Coding Agents III: Sandboxing & Best Practices

Blog

Pi has no built-in boundaries — it operates with full user permissions. Part 3 of our series shows how to run Coding Agents safely using Dev Containers, and shares hard-won best practices for productive agent workflows.

Back to Blog
March 19, 2026 | Palaimon Team | coding-agentsAIDevOpssoftware-engineering

In the previous post, we explored how Coding Agents work under the hood — System Prompts, Tools, Skills, and the Agent Loop. We saw that Pi’s run_command tool gives the agent access to any CLI command on the system. That’s powerful. It’s also dangerous.

Pi, by default, has no boundaries. It operates with the full permissions of the user running it. If your user can delete system files, so can Pi. If your user can push to production, so can Pi. This is by design — Pi trusts the operator to set appropriate constraints. But it means that sandboxing is not optional; it’s essential.

The Default Danger

Let’s be concrete about what can go wrong when you run an unbounded Coding Agent:

These risks range from common (the agent writes to an unexpected file) to rare but catastrophic (the agent modifies system files). Sandboxing protects against the full spectrum.

A sandboxing solution we’ve used extensively is Dev Containers — Docker-based development environments integrated into VS Code. Their strength is integration with editor extensions and toolchains not available on the host. Here’s how it works:

  1. Define a Dev Container for your project using a devcontainer.json configuration file. This specifies the Docker image, mounted volumes, and extensions.
  2. Open the project in the Dev Container via VS Code. The editor runs inside the container, and so does Pi.
  3. Project files are bind-mounted into the container. Both you (via VS Code on the host) and the agent (inside the container) can read and write the same files — enabling a collaborative workflow where you make manual edits while the agent works on other parts. But the agent cannot access anything outside the mount points.
  4. The container’s network, filesystem, and process namespace are isolated from the host. The agent’s run_command runs inside the container, not on your host OS. Note that the isolation isn’t absolute — by default, the container process may run as root within its namespace. For stronger isolation, consider user namespace mapping or Podman’s rootless mode.
// .devcontainer/devcontainer.json
{
  "name": "My Project",
  "image": "mcr.microsoft.com/devcontainers/python:3.11",
  "mounts": [
    "source=${localWorkspaceFolder},target=/workspace,type=bind",
    "source=${localEnv:HOME}/.config/pi,target=/home/vscode/.config/pi,type=bind"
  ],
  "workspaceFolder": "/workspace",
  "postCreateCommand": "pip install -e . && npm install -g @mariozechner/pi-coding-agent"
}

This gives the agent a Python environment, installs Pi, mounts only the project directory, and shares your Pi configuration across containers. The agent can work freely within /workspace but cannot touch the host system. Adjust the base image and postCreateCommand for your stack — the same principles apply to any language.

Startup Costs: The Honest Trade-off

Dev Containers aren’t free. The initial container build can take up to 3 minutes — the first run pulls layers and installs everything. (With a prebuilt image, even the first start can be near-instant.) For a quick 5-minute task without a prebuild, this overhead is significant.

But here’s the reality: Coding Agent sessions are rarely 5 minutes. A typical session lasts 30 minutes to several hours. In that context, a 3-minute startup is negligible. And once the container is built, subsequent starts take only ~10 seconds — VS Code caches the container image.

Session LengthStartup OverheadOverhead Ratio
5 min3 min60%
30 min3 min10%
2 hours3 min2.5%
Full day3 min<1%

The longer your session, the less the startup cost matters. And the safety benefit is constant. With Bubblewrap’s sub-second startup (covered below), even a 5-minute task incurs negligible overhead — the trade-off is weaker isolation than a full Dev Container.

Pre-Configured Environments for Teams

One of the most impactful things a team can do is pre-configure Dev Container definitions for their projects. When a new team member (or a Coding Agent) opens the project, the environment is ready: the right Python version, the right dependencies, the right tools.

This serves a dual purpose: it gives human developers a consistent environment (eliminating “works on my machine”), and it gives the agent a known-good starting point (reducing environment-level mistakes). You can also mount a shared Pi configuration folder into every Dev Container, ensuring all projects use the same Skills and agent settings. Alternatively, keep configurations separate per container — it’s a design choice.

Git Inside Containers

One subtlety: Git configuration inside a Dev Container may differ from the host. The container has its own .gitconfig, which means:

These are solvable problems, but easy to overlook until the agent’s first commit shows up as “Unknown unknown@container.”

Alternative Sandboxing Approaches

Dev Containers aren’t the only option. Here’s a technical comparison of the main approaches:

ApproachKernel IsolationGPU AccessFilesystem IsolationStartup TimeAgent Suitability
None (bare metal)✗ None✓ Native✗ None0s⚠ Dangerous
Bubblewrap◐ Namespace-level✗ Not by default✓ Bind-mount<1s✓ Lightweight tasks
Docker Dev Container✓ Namespace + cgroups✓ nvidia-container-toolkit✓ Bind-mount~3 min (cold) / ~10s (warm)✓✓ Recommended
QEMU/KVM VM✓✓ Full hypervisor✓ VFIO passthrough✓✓ Full~30s–2 min✓ Heavy isolation

Bubblewrap (bwrap) is worth a special mention. It’s a lightweight sandboxing tool that uses Linux namespaces to isolate the agent’s filesystem view — the same engine that powers Flatpak for desktop applications. It starts in under a second and requires no Docker daemon. GPU access requires explicit bind-mount (e.g., --dev-bind /dev/dri); the isolation is namespace-level only (not a full VM). For CPU-only coding tasks, it’s an excellent lightweight alternative.

Want the deep dive on Bubblewrap — how Pi configures it, why it's safer than Docker, and its Flatpak heritage? Read our dedicated Bubblewrap post.

QEMU/KVM VMs provide the strongest isolation — a full hypervisor boundary — and support GPU passthrough via VFIO. We covered this approach in detail in our post on escaping CUDA dependency hell. For Coding Agents, VMs are overkill for most use cases, but they’re the right choice when you need the agent to work with kernel-level tools or when regulatory requirements demand full isolation.

Best Practices for Productive Agent Workflows

Sandboxing keeps you safe. But safety without productivity is just bureaucracy. Through extensive use of Coding Agents at Palaimon, we’ve found the following practices effective:

1. Break Tasks into Small, Reviewable Steps

Don’t ask the agent to “implement the entire authentication module.” Instead, break it down:

Smaller tasks mean smaller diffs, easier reviews, and faster course correction when the agent goes off track.

2. Review Every Generated Change

The agent is fast, but it’s not infallible. Before accepting any change:

Treat agent-generated code with the same scrutiny you’d apply to a junior developer’s pull request. Beware of review fatigue: as you review more agent output, the temptation to rubber-stamp increases. Combat this by occasionally reviewing the final code without the diff view — read it as if a human wrote it.

3. Clear Working Memory Between Features

Pi maintains a working memory (conversation context) across the session. As the context grows, the agent’s performance can degrade — it may confuse earlier instructions with current ones, or lose track of the current task.

After completing a feature, start a fresh conversation or clear the context. This gives the agent a clean slate for the next task and prevents cross-contamination between features.

Pi’s status bar shows the current context size — use it as a gauge. The principle (clear context between features) is universal even if the mechanism differs by agent.

4. Avoid Full-Spectral Development

“Full-spectral development” — asking the agent to design, implement, test, and deploy a feature in one go — sounds appealing but has proven expensive and unreliable in practice. The agent’s context window fills up, errors compound, and the resulting code is harder to review because the diff is enormous.

Instead, use an iterative, supervised workflow:

  1. Define the task clearly
  2. Let the agent implement one step
  3. Review the result
  4. Provide feedback or move to the next step
  5. Repeat

This may seem to contradict the autonomy we celebrated in Part 1 — and in a sense, it does. The promise of Coding Agents is autonomous execution, but practice shows that supervised autonomy outperforms unsupervised autonomy. The agent is most powerful when you direct its autonomy toward well-scoped tasks. This is slower in wall-clock time per step, but faster in time to correct, production-ready code — because you catch errors early and keep the agent on track.

The Iteration Payoff

Think of it as a control system: frequent feedback keeps the agent's output close to the desired trajectory. Without feedback, small errors accumulate — and by the time you review, the agent may have built an entire edifice on a flawed foundation. Short iterations are your error correction signal.

The Bottom Line

Coding Agents are powerful tools, but power without boundaries is a liability. Dev Containers provide the right balance of isolation and usability for most development workflows. Combined with disciplined task decomposition, regular reviews, and context management, they enable you to harness the agent’s capabilities without putting your system at risk.

You know what Coding Agents are, how they work, and how to run them safely. But for companies, the real question is strategic: ban them, buy them, or build internal expertise? In the next post, we’ll explore the three paths enterprises can take.