In Praise of Containers; there's no place like $HOME

Vintage illustration from The Internet Guide for New Users

Our team has a bit of a disagreement on using containers for agentic coding.

We all prefer coding with our settings "just so." We've got our vimrc's, our bashrc's, our bookmarks, our "set -o vi"'s, our gitconfig's, our color schemes, our prompts… coding on our own machines is better.

And yet we've all experienced the opposite: a CI job, failing mysteriously every tenth build, on a machine where you can't get at the logs or the noisy neighbours. (Perhaps we've even used tmate (see https://blog.philz.dev/blog/ci-debugging/) to break in, or perhaps we're inspired and have set up a Go SSH server that embeds a tailscale funnel (a la https://tailscale.dev/blog/embedded-funnel...).

And there's the in between, too: we develop on a Mac, but need strace (and don't want to disable System Integrity Protection to use dtruss) or want to use subtrace, which requires eBPF, or just want the same version of Python that's in our deployment environment… and we end up working semi-remotely in a Linux VM or container one way or another…

And, so, when we're working with agentic coding assistants, do we want the agents to work in a container or on our local machine? Our coding agent has been defaulting to container, and I think that's the right call, though contentious! I have found a few key features make working with an agent at a distance not just palatable, but better than working locally.

Accessible Containers

Both local and hosted Sketch containers are accessible via SSH as well as a terminal in the web UI. If you need to login to fly.io, or manually do some git operations, those access points are sufficient. (My esoteric favorite is "git fetch ssh://root@sketch-ebmc-zv4m-y7w9-ysdt/app" followed by operations with FETCH_HEAD.)

Providing SSH access also gives you VSCode integration, with VSCode remoting. Sketch sessions offer a link in the UI to open up the project with VSCode. We'll be honest: it's not as good as VSCode locally, but it works for code navigation.

A corollary is that the containers shouldn't disappear while you're still working on the problem. If the containers are too ephemeral, that is, if they're only around while the agent is doing its job, you don't get a chance to inspect what's going on if you need to.

Pretty Good Diffs

If you're reviewing the code the agent is writing, you need to look at diffs. Sketch's right-hand-editable diffs use Monaco to give you a pretty good editor experience at looking at the diffs, and, importantly, to leave comments for the agent.

HTTP Proxies

When the agent starts an HTTP server, Sketch detects an open port, and proxies it to a new, unique, TLS-protected endpoint that only you (and, eventually, anyone you share it with) has access to.

This feels like magic. No port conflicts; works from your phone if you want to test mobile; it's seamless.

Custom Base Images

Sketch (currently only in local mode) lets you specify a base image to use. For the most part, agents are great at installing what you need, but, to save time and money, you can bake that into an image. You need something very similar to this image for CI anyway, and you can usually ask the agent to generate it based on what it finds in github workflows and such.

A Browser Tool

Some of the container-less agents I've used have started a web server, and asked me ever so politely to open up my browser and go look at it. That's not how this works… the agent should use its own browser to go look at it. I've not found Anthropic's models to have a keen eye for identifying failing CSS styles, but loading the page and checking the console logs, and verifying the text gets you a long, long way. (You can, of course, do this locally by providing the Playwright MCP.)

A Tabular Comparison

Put in tabular form, here are some advantages for each way of running agents. There are, of course, nuances to all of these.

Local Containers
Familiar: your existing tools, configs, etc. are already present. There is less cognitive load. Isolation: harder for the agent to break your machine or break into your cookie jar
Pairable: you can work "with" the agent and switch off doing tasks Parallelism: easy to run multiple, potentially conflicting tasks, at the same time
Quickstartable: you already develop on your machine, so, by definition, the agent can make progress without having to install things Configuration Shareability: can share a container image that works well
Hostable: containers can be hosted elsewhere, so you can kick off an idea from your phone, for example

So, which is better?

I use both. Containers let me work without evaluating "do I want to let my agent run command x" all the time, because I know the container has limited permissions to begin with. Containers let me experiment with runtimes and frameworks that I have no immediate intention of learning how to install on my laptop. Containers let me work in parallel without worrying about the state of my git repo. On the one hand, with containers, I'll have to use git to get the changes back. On the other hand, without containers, I'll have to use git to figure out what the agent did and what I was doing, and why did I start the agent in a dirty workspace, oh my goodness. If I'm in the midst of a thing in the editor, however, and I need the agent to do a small task, the container feels cumbersome, and I'll reach for a local agent…

What do you think?

We'd love to hear your thoughts on containers vs. local development for agentic coding! Fill out our quick form to share your experience and preferences.

The image at the top of this blog post is from The Internet Guide for New Users by Daniel P. Dern.