{"id":4716,"date":"2026-08-03T13:11:56","date_gmt":"2026-08-03T13:11:56","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/08\/03\/empty-sandboxes-break-developer-experience\/"},"modified":"2026-08-03T13:11:56","modified_gmt":"2026-08-03T13:11:56","slug":"empty-sandboxes-break-developer-experience","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/08\/03\/empty-sandboxes-break-developer-experience\/","title":{"rendered":"Empty sandboxes break developer experience"},"content":{"rendered":"<p class=\"wp-block-paragraph\">I work on <a href=\"https:\/\/docs.docker.com\/ai\/sandboxes\/\" rel=\"nofollow noopener\" target=\"_blank\">Docker Sandboxes<\/a>, so I spend a lot of time talking about isolation, microVMs, disposable filesystems, blast radii, all the good infrastructure things.<\/p>\n<p class=\"wp-block-paragraph\">But the Docker Sandboxes feature I keep reaching for in daily use is <a href=\"https:\/\/docs.docker.com\/ai\/sandboxes\/customize\/kits\/\" rel=\"nofollow noopener\" target=\"_blank\">kits<\/a>.<\/p>\n<p class=\"wp-block-paragraph\">Kits sound like a packaging detail until you try to use a sandbox for real work. An empty sandbox is a good boundary. It\u2019s also (eventually) ephemeral and empty, and that combination means annoyance and repeated setup work.<\/p>\n<p class=\"wp-block-paragraph\">The agent gets a clean filesystem, a baseline restricted network, and a clean credentials environment. Then it immediately needs <code>gcloud<\/code>, Java, Maven, some internal CLI, your package registry credentials, and that one skill where you distilled the tacit knowledge your team accumulated for years.<\/p>\n<p class=\"wp-block-paragraph\">Kits are the escape hatch from that ritual. A kit lets you describe what the sandbox needs, how it should get it, what it may reach, and which credentials it can use, then apply that description when the sandbox starts.<\/p>\n<h2 class=\"wp-block-heading\">Empty means setup work<\/h2>\n<p class=\"wp-block-paragraph\">The usual sandboxing story is security-shaped: put the risky thing behind a boundary and limit the blast radius.<\/p>\n<p class=\"wp-block-paragraph\">Developers rarely keep using tools because the architecture diagram has a nice boundary on it. They keep using tools when the workflow is less annoying than the alternative.<\/p>\n<p class=\"wp-block-paragraph\">A blank sandbox starts from a place developers rarely start from in practice. Real developer machines have: SDKs, package managers, cloud CLIs, shell setup, local credentials, project docs, cached tools, and configuration nobody wants to reconstruct from memory. Some of it is good engineering. Some of it is archaeology. Both affect whether the agent can complete the task.<\/p>\n<p class=\"wp-block-paragraph\">The failure is rarely dramatic. The agent spends a few minutes installing packages, hits a blocked registry, asks for an API key it should never see, and the sandbox starts to feel like the thing between you and the work.<\/p>\n<p class=\"wp-block-paragraph\">At that point, the developer has a choice: spend ten minutes preparing the isolated environment, or run the agent on the host and move on with their life.<\/p>\n<p class=\"wp-block-paragraph\">We all know which one will win.<\/p>\n<h2 class=\"wp-block-heading\">What is an sbx kit?<\/h2>\n<p class=\"wp-block-paragraph\">The <a href=\"https:\/\/docs.docker.com\/ai\/sandboxes\/customize\/kits\/\" rel=\"nofollow noopener\" target=\"_blank\">kits docs<\/a> describe a kit as a <code>spec.yaml<\/code> plus optional files. The useful mental model is simpler: a kit is the contract between the sandbox and the tool you want available inside it.<\/p>\n<p class=\"wp-block-paragraph\">A kit can install tools:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; gutter: false; title: ; notranslate\">\nschemaVersion: \"1\"\nkind: mixin\nname: jq\n\ncommands:\n  install:\n    - command: \"apt-get update &amp;amp;&amp;amp; apt-get install -y jq\"\n\n<\/pre>\n<\/div>\n<p class=\"wp-block-paragraph\">That is the smallest version. Useful kits usually do more. They can drop files into <code>\/home\/agent\/<\/code> or the workspace, set non-secret environment variables, run startup commands, start background services, and add agent context to files such as <code>CLAUDE.md<\/code> or <code>AGENTS.md<\/code>.<\/p>\n<p class=\"wp-block-paragraph\">They can also describe the outside world the sandbox is allowed to touch:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; gutter: false; title: ; notranslate\">\nnetwork:\n  allowedDomains:\n    - api.example.com\n    - \"*.cdn.example.com\"\n  deniedDomains:\n    - telemetry.example.com\n<\/pre>\n<\/div>\n<p class=\"wp-block-paragraph\">And they can connect credentials without copying real secrets into the microVM. The standard pattern keeps the credential on the host, gives the agent a sentinel value, and lets the sandbox proxy inject the real header only when the request goes to an approved service.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; gutter: false; title: ; notranslate\">\nnetwork:\n  allowedDomains:\n    - api.example.com\n  serviceDomains:\n    api.example.com: my-service\n  serviceAuth:\n    my-service:\n      headerName: Authorization\n      valueFormat: \"Bearer %s\"\n\ncredentials:\n  sources:\n    my-service:\n      env:\n        - MY_SERVICE_API_KEY\n\nenvironment:\n  proxyManaged:\n    # Agent sees \"proxy-managed\"; the host proxy injects the real token.\n    - MY_SERVICE_API_KEY\n\n<\/pre>\n<\/div>\n<p class=\"wp-block-paragraph\">Inside the sandbox the agent sees <code>MY_SERVICE_API_KEY=proxy-managed<\/code>. The actual secret stays on the host. The proxy replaces the header on the way out.<\/p>\n<p class=\"wp-block-paragraph\">That distinction is why credential support belongs in the kit contract. If the sandbox exists to keep the agent away from host secrets, copying those secrets into the microVM would be a strange way to celebrate.<\/p>\n<div class=\"wp-block-ponyo-image\">\n                <img data-opt-id=1173101287  fetchpriority=\"high\" decoding=\"async\" width=\"2320\" height=\"705\" src=\"https:\/\/www.docker.com\/app\/uploads\/2026\/08\/Screenshot-2026-07-31-at-23.05.29-2320x705.png\" class=\"fade-in\" alt=\"Screenshot 2026 07 31 at 23.05.29\" title=\"- Screenshot 2026 07 31 at 23.05.29\" \/>\n        <\/div>\n<p class=\"wp-block-paragraph\">\n<h2 class=\"wp-block-heading\">Mixin kits are the norm<\/h2>\n<\/p><p class=\"wp-block-paragraph\">There are two kit shapes in the spec. A <code>kind: sandbox<\/code> kit defines a full agent runtime: image, entrypoint, policy, the whole thing. Use that when you are building an agent.<\/p>\n<p class=\"wp-block-paragraph\">Most integrations should be mixins.<\/p>\n<p class=\"wp-block-paragraph\">A mixin kit extends an existing sandbox with one capability. It installs the tool, opens the narrow network path, wires credentials, and gives the agent enough instructions to use the thing. The runtime stays with the agent kit.<\/p>\n<p class=\"wp-block-paragraph\">That is the shape I use for most of my own kits. For example, the kits I keep using daily are <a href=\"https:\/\/github.com\/shelajev\/agy-sbx-kit\" rel=\"nofollow noopener\" target=\"_blank\"><code>agy<\/code><\/a>, <a href=\"https:\/\/github.com\/shelajev\/yt-transcript-sbx-kit\" rel=\"nofollow noopener\" target=\"_blank\"><code>yt-transcript<\/code><\/a>, and <a href=\"https:\/\/github.com\/shelajev\/tessl-sbx-kit\" rel=\"nofollow noopener\" target=\"_blank\"><code>tessl<\/code><\/a>.<\/p>\n<p class=\"wp-block-paragraph\">The YouTube kit is exactly what you think: give the sandbox the tools to fetch transcripts and media metadata without turning every new sandbox into a small dependency archaeology project. The Tessl kit is even more direct. It brings skills into the agent running inside the sandbox, so I do not need to inject them manually like a medieval peasant.<\/p>\n<p class=\"wp-block-paragraph\">The nice part of mixins is that they stack.<\/p>\n<p class=\"wp-block-paragraph\">A giant \u201cOleg\u2019s entire laptop, but in a microVM\u201d kit would be funny once and then become a maintenance incident. You want small kits with clear jobs:<\/p>\n<ul class=\"wp-block-list\">\n<li>a Java kit that installs a JDK, Maven, SDKMAN!, team Maven settings, and links to Spring docs;<\/li>\n<li>a <code>gcloud<\/code> kit that installs the CLI, allows the right Google API domains, and wires credentials through the proxy;<\/li>\n<li>a Google Workspace kit that gives the agent access to your email and Google Docs;<\/li>\n<li>a Tessl kit that brings skills into the sandbox;<\/li>\n<li>a YouTube transcript kit that adds <code>yt-dlp<\/code>, <code>ffmpeg<\/code>, and whatever network access those need.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">Then a sandbox can be assembled for the task:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; gutter: false; title: ; notranslate\">\nsbx run claude . \n  --kit docker.io\/acme\/sbx-java-kit:1.0 \n  --kit docker.io\/acme\/sbx-gcloud-kit:1.0 \n  --kit docker.io\/acme\/sbx-tessl-kit:1.0\n\n<\/pre>\n<\/div>\n<p class=\"wp-block-paragraph\">The same agent now starts with a different contract around it.<\/p>\n<p class=\"wp-block-paragraph\">At that point kits stop being a packaging mechanism and start being a productivity feature. The sandbox stays disposable, but the setup becomes repeatable. The developer can throw away the environment without throwing away the knowledge of how to rebuild it.<\/p>\n<h2 class=\"wp-block-heading\">Sharing is caring<\/h2>\n<p class=\"wp-block-paragraph\">Local setup scripts are fine until the second person needs them. At that point they become documentation, and documentation becomes stale with excellent punctuality. Then someone pastes a token into a config file because the happy path was missing.<\/p>\n<p class=\"wp-block-paragraph\">A kit gives that setup a place to live.<\/p>\n<p class=\"wp-block-paragraph\">Vendors can publish kits for their CLIs or APIs. Inside a company, the same pattern works for package registries, cloud accounts, corporate proxy certificates, and preferred language toolchains. The user gets one <code>--kit<\/code> flag instead of a wiki page and a feeling of mild dread.<\/p>\n<p class=\"wp-block-paragraph\">Distribution matters here. Kits support local directories, Git URLs, and OCI artifacts. For shared kits, OCI distribution is the obvious path because users can reference a versioned artifact directly:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; gutter: false; title: ; notranslate\">\nsbx run claude --kit docker.io\/acme\/sbx-my-product-kit:1.0\n\n<\/pre>\n<\/div>\n<p class=\"wp-block-paragraph\">Keep the source in GitHub or wherever your team collaborates. Publish the artifact to Docker Hub or another OCI registry. The source repo is where people review, patch, and complain politely. The registry is what makes the kit easy to consume.<\/p>\n<h2 class=\"wp-block-heading\">All in all<\/h2>\n<p class=\"wp-block-paragraph\">Security is a good reason to care about kits. The network and credential contract becomes explicit, which is useful by itself. The daily-use reason is more prosaic: kits make sandboxes survivable as a development tool.<\/p>\n<p class=\"wp-block-paragraph\">An empty sandbox is a boundary. A configured sandbox is a place where an agent can actually work. Kits are how that configuration becomes repeatable, reviewable, and shareable.<\/p>\n<p class=\"wp-block-paragraph\">The <a href=\"https:\/\/docs.docker.com\/ai\/sandboxes\/customize\/kits\/\" rel=\"nofollow noopener\" target=\"_blank\">kits docs<\/a> and <a href=\"https:\/\/docs.docker.com\/ai\/sandboxes\/customize\/kit-examples\/\" rel=\"nofollow noopener\" target=\"_blank\">examples<\/a> are enough to build a first mixin kit without inventing the shape from scratch.<\/p>\n<p class=\"wp-block-paragraph\">Isolation only survives contact with developers when it is at least as convenient as skipping it.<\/p>","protected":false},"excerpt":{"rendered":"<p>I work on Docker Sandboxes, so I spend a lot of time talking about isolation, microVMs, disposable filesystems, blast radii, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":4717,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[4],"tags":[],"class_list":["post-4716","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/4716","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=4716"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/4716\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media\/4717"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=4716"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=4716"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=4716"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}