Improving the Developer Experience with SBX Kits

sbx

In previous articles, we walked step by step through setting up a secure, isolated web development environment (Web IDE) with sbx, integrating a development agent based on docker-agent and Docker Model Runner, creating an sbx sandbox template, and giving it specific capabilities through “mini skills”.

A brand new sbx feature: Kits, which let you customize sbx sandboxes by adding specific capabilities in a simple, reusable way (tools to install, environment variables, credentials to inject, domains to allow, files, startup commands, etc).

This means, for example, that we can remove the development tools (editors, languages, etc) from our sbx sandbox template (Dockerfile) and put them in a separate kit, which we can then reuse across other sbx sandbox templates.

New sbx sandbox template

So I started by simplifying the sbx sandbox template we created in previous articles, to make a new, more generic one that only contains the base elements along with the Web IDE (Code Server) and docker-agent:

FROM docker/docker-agent:1.54.0 AS coding-agent

FROM --platform=$BUILDPLATFORM docker/sandbox-templates:shell

LABEL maintainer="@k33g_org"

ARG USER_NAME=agent

ENV TERM=xterm-256color
ENV COLORTERM=truecolor

ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US.UTF-8
ENV LC_COLLATE=C
ENV LC_CTYPE=en_US.UTF-8

USER root

RUN <<EOF
apt-get update
apt-get install -y wget curl build-essential xz-utils software-properties-common
rm -rf /var/lib/apt/lists/*
EOF

# ------------------------------------
# Install code-server
# ------------------------------------
RUN curl -fsSL https://code-server.dev/install.sh | sh

# ------------------------------------
# Install docker-agent
# ------------------------------------
COPY --from=coding-agent /docker-agent /usr/local/bin/docker-agent

# Switch to the regular user
USER ${USER_NAME}

# ------------------------------------
# Install OhMyBash
# ------------------------------------
RUN <<EOF
bash -c "$(curl -fsSL https://raw.githubusercontent.com/ohmybash/oh-my-bash/master/tools/install.sh)"
EOF

EXPOSE 8080

You can find the code here: Dockerfile

Then we need to build and publish our new image:

DOCKER_HANDLE=k33g
TAG=0.0.0
NAME=sbx-bill
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t ${DOCKER_HANDLE}/${NAME}:${TAG} --push .

Replace DOCKER_HANDLE, NAME, and TAG with whatever values you want (you can also put them in a .env file for convenience).

Now let’s move on to creating the sbx kit that will install the development tools in our sbx sandbox at launch time.

Creating the sbx kit

We’re going to define an sbx kit that will install development tools (Go, Node.js, etc) in our sbx sandbox when it starts. This means the first sandbox launch will take a bit longer than usual since it needs to install the tools, but we gain flexibility — and the ability to modify the kit without having to rebuild the template.

So I created a new bill folder (following the same pattern as bob and riker from previous articles), with a config.yaml configuration file for docker-agent. I then added a kit subfolder (you can name it whatever you want) with a spec.yaml specification file that describes what to add to the sbx sandbox at launch:

bill
├── config.yaml
├── kit
   └── spec.yaml
└── README.md

What I need in my sbx sandbox is the following tools:

And finally, the Code Server development server needs to start each time the sbx sandbox launches.

sbx kit specification

Here’s what the spec.yaml specification file for my sbx kit looks like:

schemaVersion: "1"
kind: agent
name: we-are-legion
displayName: Bill [We are legion]
description: Bill, a first generation clone of Bob

network:
  allowedDomains:
    - host.docker.internal:12434

agent:
  image: docker.io/k33g/sbx-bill:0.0.0

environment:
  variables:
    GOROOT: /usr/local/go
    GOPATH: /home/agent/go

commands:
  install:
    # Go
    - command: "wget https://golang.org/dl/go1.26.2.linux-arm64.tar.gz -O /tmp/go.tar.gz && tar -xf /tmp/go.tar.gz -C /tmp && mv /tmp/go /usr/local && rm /tmp/go.tar.gz"
      user: "0"
      description: Install Go

    # Add Go to the persistent PATH (used by subsequent install commands)
    - command: "echo 'export PATH=/usr/local/go/bin:/home/agent/go/bin:$PATH' >> /etc/sandbox-persistent.sh"
      user: "0"
      description: Persist Go PATH

    # Node.js via nodesource
    - command: "apt-get update && apt-get install -y ca-certificates curl gnupg && curl -fsSL https://deb.nodesource.com/setup_25.x | bash - && apt-get install -y nodejs"
      user: "0"
      description: Install Node.js

    # Go tools (gopls, etc.)
    - command: "PATH=/usr/local/go/bin:$PATH GOPATH=/home/agent/go go install golang.org/x/tools/gopls@latest && go install github.com/ramya-rao-a/go-outline@latest"
      user: "1000"
      description: Install Go tools

    # code-server extensions (download VSIX from Open VSX)
    - command: |
        mkdir -p /tmp/vsix
        curl -fsSL -o /tmp/vsix/material-icons.vsix \
          https://open-vsx.org/api/PKief/material-icon-theme/5.33.1/file/PKief.material-icon-theme-5.33.1.vsix
        curl -fsSL -o /tmp/vsix/material-product-icons.vsix \
          https://open-vsx.org/api/PKief/material-product-icons/1.7.1/file/PKief.material-product-icons-1.7.1.vsix
        curl -fsSL -o /tmp/vsix/go-ext.vsix \
          https://open-vsx.org/api/golang/Go/0.52.2/file/golang.Go-0.52.2.vsix
        code-server \
          --install-extension /tmp/vsix/material-icons.vsix \
          --install-extension /tmp/vsix/material-product-icons.vsix \
          --install-extension /tmp/vsix/go-ext.vsix
        rm -rf /tmp/vsix
      user: "1000"
      description: Install code-server extensions


  startup:
    - command: ["sh", "-c", "code-server --auth none --bind-addr 0.0.0.0:8080 \"${SBX_PROJECT_DIR:-${PWD:-$HOME}}\" > /tmp/code-server.log 2>&1"]

      user: "1000"
      background: true
      description: Start code-server on port 8080

sbx kit walkthrough

Header / Manifest

schemaVersion: "1"
kind: agent
name: we-are-legion
displayName: Bill [We are legion]
description: Bill, a first generation clone of Bob
Field Value Why
schemaVersion "1" Current and only version of the spec schema. Always "1".
kind agent Declares an autonomous agent (image + full configuration). The mixin alternative enriches an existing agent without defining a new one.
name we-are-legion Machine identifier used by sbx to reference the kit (e.g. sbx create --kit ./we-are-legion). No spaces or uppercase.
displayName Bill [We are legion] Name displayed in interfaces (CLI, UI).
description Bill, a first generation clone of Bob Description text.

agent

agent:
  image: docker.io/k33g/sbx-bill:0.0.0

image: the base Docker image the kit is applied on.

environment

environment:
  variables:
    GOROOT: /usr/local/go
    GOPATH: /home/agent/go

These variables are injected as container environment variables at startup, equivalent to ENV instructions in a Dockerfile.

Variable Value Why
GOROOT /usr/local/go Points to the Go installation directory. That’s where wget + tar drops the official archive. Conventional value for manual Go installations.
GOPATH /home/agent/go Go user workspace: holds downloaded modules (pkg/) and installed binaries (bin/). Placed in the agent user’s home (uid 1000) to avoid permission issues.

Important: these variables don’t modify PATH automatically. PATH is managed separately via /etc/sandbox-persistent.sh (see install section).

commands

commands.install

install commands run once, at sandbox creation (sbx create). They’re the equivalent of RUN instructions in a Dockerfile, but applied to the base image at runtime rather than build time.

Installing Go
- command: "wget https://golang.org/dl/go1.26.2.linux-arm64.tar.gz -O /tmp/go.tar.gz && tar -xf /tmp/go.tar.gz -C /tmp && mv /tmp/go /usr/local && rm /tmp/go.tar.gz"
    user: "0"
    description: Install Go
Persisting Go in PATH
- command: "echo 'export PATH=/usr/local/go/bin:/home/agent/go/bin:$PATH' >> /etc/sandbox-persistent.sh"
    user: "0"
    description: Persist Go PATH
Installing Node.js
- command: "apt-get update && apt-get install -y ca-certificates curl gnupg && curl -fsSL https://deb.nodesource.com/setup_25.x | bash - && apt-get install -y nodejs"
    user: "0"
    description: Install Node.js
Installing Go tools
- command: "PATH=/usr/local/go/bin:$PATH GOPATH=/home/agent/go go install golang.org/x/tools/gopls@latest && go install github.com/ramya-rao-a/go-outline@latest"
    user: "1000"
    description: Install Go tools
Installing code-server extensions
- command: |
    mkdir -p /tmp/vsix
    curl -fsSL -o /tmp/vsix/material-icons.vsix \
        https://open-vsx.org/api/PKief/material-icon-theme/5.33.1/file/PKief.material-icon-theme-5.33.1.vsix
    curl -fsSL -o /tmp/vsix/material-product-icons.vsix \
        https://open-vsx.org/api/PKief/material-product-icons/1.7.1/file/PKief.material-product-icons-1.7.1.vsix
    curl -fsSL -o /tmp/vsix/go-ext.vsix \
        https://open-vsx.org/api/golang/Go/0.52.2/file/golang.Go-0.52.2.vsix
    code-server \
        --install-extension /tmp/vsix/material-icons.vsix \
        --install-extension /tmp/vsix/material-product-icons.vsix \
        --install-extension /tmp/vsix/go-ext.vsix
    rm -rf /tmp/vsix
    user: "1000"
    description: Install code-server extensions
Extension Role
material-icon-theme File icons in the explorer (PKief theme)
material-product-icons code-server UI icons
golang.Go Full Go support: autocompletion, formatting, debugging, linting
commands.startup

startup commands run on every sandbox start. They’re used to launch background processes or initialize the session environment.

startup:
  - command: ["sh", "-c", "code-server --auth none --bind-addr 0.0.0.0:8080 \"${SBX_PROJECT_DIR:-${PWD:-$HOME}}\" > /tmp/code-server.log 2>&1"]

    user: "1000"
    background: true
    description: Start code-server on port 8080

Launching our new sbx sandbox with the kit

This time, the commands to launch our web development environment are much simpler:

sbx create --kit ./kit we-are-legion .

Then we can expose the code-server port to access it from the host with sbx ports:

current_dir=$(basename "$PWD")
published_port=6060

# we-are-legion-${current_dir} is the name of the sandbox
sbx ports we-are-legion-${current_dir} --publish ${published_port}:8080/tcp
echo "http://localhost:${published_port}/?folder=$(pwd)"

And we can open our Web IDE in a browser at http://localhost:6060:

sbx

We can verify that everything is installed and working (Go, Node.js, …) by opening a terminal in code-server:

sbx

And finally launch our docker-agent:

sbx

Conclusion

We now have everything we need to spin up secure on-demand web development environments with a code agent TUI using a local language model via Docker Model Runner, all inside an sbx sandbox that’s fully customizable through a kit.

The source code used in this blog post is available here: we-are-legion/bill.

sbx Kits are a very powerful feature and I’ve barely scratched the surface. I encourage you to check out the official documentation: Customizing sandboxes with Kits.

© 2026 k33g Project | Built with Gu10berg

Subscribe: 📡 RSS | ⚛️ Atom