A lightweight CLI that launches and manages devcontainers using the Docker Engine API directly. No Node.js, no VS Code — just a single binary and Docker.
The official devcontainer CLI requires Node.js and npm. devc is a standalone Go binary (~12MB) that talks to Docker directly.
- Zero runtime dependencies — Docker is all you need
- User-level config — Global features, dotfiles, and mounts shared across all projects
- In-container CLI — Forward ports, run host commands, and trigger rebuilds from inside the container
- Full devcontainer.json support — Image, Dockerfile, and Docker Compose modes with OCI features
gh release download --repo KUCHITAKE/devc -p 'devc_*_linux_amd64.tar.gz'
tar xzf devc_*.tar.gz && install -Dm755 devc ~/.local/bin/devcBinaries are available for linux/amd64, linux/arm64, darwin/amd64, and darwin/arm64.
git clone https://github.com/KUCHITAKE/devc.git && cd devc
make install # builds in Docker, installs to ~/.local/bin/devcdevc up ~/project # start container & attach
devc up -p 3000:3000 -p 5173 ~/project # with port forwarding
devc rebuild ~/project # rebuild from scratch
devc down ~/project # remove containers & networks (volumes preserved)
devc clean ~/project # remove container & volumes| Command | Description |
|---|---|
up [flags] [dir] |
Start container and attach (default) |
down [dir] |
Remove containers & networks, keep volumes |
clean [dir] |
Remove container and volumes |
rebuild [dir] |
Alias for up --rebuild |
| Flag | Description |
|---|---|
-p, --publish |
Publish ports (e.g., -p 3000:3000). Repeatable |
--rebuild |
Force rebuild, discard cached image |
-f, --force |
Launch even if a host port conflicts with a running workspace |
Ports are collected from multiple sources (CLI flags take precedence):
-pflagsforwardPortsin devcontainer.jsonappPortin devcontainer.json
Bare ports (e.g., 3000) auto-detect an available host port, incrementing if the preferred port is in use.
Before starting, up checks the ports it is about to publish (including the
compose services' own ports) against other running devc workspaces — handy when
the same repo is checked out into several directories. A conflict on a fixed
host:container port aborts the launch (override with --force); a bare port
just remaps as above. ls/ps lists both image- and compose-based workspaces,
one row per workspace.
When inside a devc container, the devc binary is available with a different set of commands:
| Command | Description |
|---|---|
devc info |
Show container metadata (project, image, ports, features) |
devc env |
Show injected environment variables |
devc port <port> |
Forward a port dynamically (e.g., devc port 8080) |
devc host <cmd> |
Execute a command on the host machine |
devc dotfiles sync |
Re-sync dotfile symlinks |
devc rebuild |
Request a rebuild on next exit |
devc supports all three devcontainer modes:
Image-based:
Custom Dockerfile:
{
"build": {
"dockerfile": "Dockerfile",
"context": "..",
"args": { "VARIANT": "3.11" },
"target": "dev"
}
}Docker Compose:
{
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"runServices": ["app", "db"],
"overrideCommand": true
}The following devcontainer.json lifecycle hooks are supported (string, array, and object forms):
onCreateCommand— runs on first container creationpostCreateCommand— runs after creationpostStartCommand— runs on every start (including restarts)
User-level settings that apply to all projects:
{
"features": {
"ghcr.io/duduribeiro/devcontainer-features/neovim:1": { "version": "nightly" },
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"dotfiles": [
"~/.config/nvim",
"~/.ssh"
],
"mounts": [
{ "source": "~/work", "target": "/home/user/work" }
]
}- features — OCI features injected into every container (project-level features take precedence on conflict)
- dotfiles — Paths mounted into the container and symlinked into the user's home directory
- mounts — Additional bind mounts
Git credentials (user.name, user.email) and GitHub CLI tokens (gh auth token) are automatically forwarded to the container.
devc runs a Unix socket daemon on the host (/tmp/devc-daemon-{id}/devc.sock) that is mounted into the container. This daemon enables:
- Dynamic port forwarding from inside the container
- Host command execution via
devc host <cmd> - Rebuild requests via
devc rebuild
The socket is only accessible from within the container that mounts it. This is an intentional design — devc containers can execute arbitrary commands on the host through this socket. This is equivalent to mounting the Docker socket, which many devcontainer setups already do.
If you run untrusted code inside a devc container, be aware that it has host access through this mechanism.
Only Docker is required to build and test. No local Go installation needed.
make build # build binary in Docker
make test # run tests in Docker
make lint # run golangci-lint in Docker
make install # build & install to ~/.local/bin/devc
make clean-cache # remove Go module/build cache volumes
{ "image": "mcr.microsoft.com/devcontainers/base:ubuntu", "features": { "ghcr.io/devcontainers/features/go:1": {} }, "forwardPorts": [3000], "remoteUser": "vscode" }