The lightweight, native Go CLI for devcontainers
Like the convenience and reproducibility devcontainers can provide, but prefer Emacs, Vim, Helix, etc.? Not a fan of Node.js or the mess that is
node_modules?Would you rather use podman for its more security-minded approach? Or maybe you wouldn’t be caught dead using anything other than FreeBSD?
If any of those are true for you, you might like
brig.

TL;DR: Get it,
cdinto your project, runbrig, enjoy devcontainers.
brig reads your devcontainer.json configuration and spins up a containerized development environment. It is designed as a standalone, dependency-free alternative to the official command-line tool with first-class support for podman and rootless workflows.
These docs are also available on https://nlsantos.github.io/brig/
Table of contents
Prerequisites
Before installing brig, ensure you have the following:
- OCI container runtime that implements Docker’s REST API: A running instance of podman (highly recommended) or Docker.
- An accessible networking socket: See instructions for enabling podman’s socket on *nix.
Quick start
Via Go
go install github.com/nlsantos/brig/cmd/brig@latest
Via Homebrew
brew install nlsantos/tap/brig
Manual install
Download the latest release for your platform and extract the binary to a directory in your $PATH (e.g., ~/.local/bin).
Usage
-
cdinto a directory with adevcontainer.json. -
Run
brig. -
Wait for the build to complete. Once finished, your terminal will be attached to the devcontainer.
⚠️ Note on persistence:
brigtreats containers as ephemeral. When you exit the shell, the container is removed. Ensure all persistent work is saved in your project directory (which is mounted) or defined in thedevcontainer.jsonconfiguration.
Options
- Help: Run
brig --helpto see all supported flags. - Configuration:
briglooks for abrigrcconfiguration file in${HOME}/.config/brigrc,${HOME}/.brigrc, or${USERPROFILE}/.brigrc. See brigrc for a sample.
Why use brig?
- Lightweight & Fast: Unlike the official command-line tool,
brigis a single static binary. It installs instantly, starts up immediately, and requires no massive dependency tree. - Minimalist Design: Built along the lines of the Unix philosophy of building one thing that does one thing well,
brigstrives to do its job and get out of your way. - Editor Agnostic:
brigunlocks the powerful and convenient workflow enabled by devcontainers to users of Emacs, Vim, Helix, and other editors. - Security Focus: Built with podman in mind,
brig’s implementation choices are made in alignment with podman’s design of running containers as a regular user. This aligns well with usage in highly locked-down environments (e.g., company-issued workstations). - FreeBSD Support: With podman being available in FreeBSD, users who prefer a *nix-based operating system have another choice beyond GNU/Linux and macOS.
brigcan help maintain a similar workflow to those using Windows and Visual Studio Code.
Podman-first design
The devcontainer spec is written primarily with the assumption that the underlying container platform is Docker. brig was built to treat podman as a first-class citizen.
I prefer podman for its rootless design. While brig uses Moby’s packages and the Docker REST API, development prioritizes compatibility with podman. If the Moby packages ever become incompatible with Podman, brig will remain on the latest version that is.
To summarize, Docker support is achieved via Podman’s compatibility with the Docker REST API and Moby packages. While brig works seamlessly with Docker, feature development prioritizes Podman’s rootless architecture.
Features
While brig is currently in alpha, it supports the core devcontainer workflow:
- Spec compliance: Validates
devcontainer.jsonconfiguration against the official schema. - Container lifecycle: Builds images (via
dockerFile) or pull images from remote registries (viaimage) and creates containers, using Git metadata when possible. - Container configuration: Supports
capAdd,privilegedmode,mounts,containerEnv. - Networking: Binds ports specified in
appPortsandforwardPorts. - Variable expansion: Robust variable expansion inspired by standard Unix shells powered by mvdan/sh.
For a more expansive list of features, refer to docs/features.md.
Alternatives
- vs. devcontainers/cli: As the reference implementation, the official command-line tool implements all the features of the spec, but requires the Node.js runtime.
brigis a compiled Go binary, making it faster to deploy and simpler to manage. - vs. UPwith-me/Container-Maker:
cmimplements features that are tangential to the core devcontainer workflow; while the bells and whistles are nice (and very impressive), I prefer a tool more aligned to the Unix philosophy.
Incompatibilities
These are the known differences with the observed behavior of Visual Studio Code and/or the official devcontainer command-line tool.
Port Management & Networking
brig differs from the official spec regarding port forwarding and privilege elevation to strictly adhere to rootless security principles.
- No privilege elevation:
brigwill not attempt to gain elevated privileges to bind low-numbered ports. - Privileged ports remapping: Instead of privilege elevation,
brigoffsets the port number on host side by a preset figure (defaults to8000but can be set via the-por--port-offsetflags). appPortvsforwardPorts:brigprefersappPortfor predictable host mapping.
For a detailed technical explanation of these design choices, see docs/ports.md.
Ephemeral containers
brig treats devcontainers as ephemeral, unlike Visual Studio Code (and possibly the official command-line tool), which keeps stopped containers to start later.
This aligns with the “cattle, not pets” philosophy for development environments, and encourages devcontainers to be stateless and reproducible.
No dedicated build step
Changes to devcontainer.json take effect immediately on the next run. There is no separate “Rebuild Container” step required; just run brig again.
No runArgs support
The runArgs field (arbitrary Docker CLI flags) is not supported because brig interacts with the engine via the REST API. Direct API equivalents (where applicable) are implemented via specific fields (like capAdd) instead.
Originally written because I’m an Emacs and podman user and don’t want to have to deal with Node.js.