Releases: gambtho/herdr-devcontainer
Release list
v0.2.0 — stop the whole Compose project
Important
prefix+S now stops more than it used to. On a Compose-based Dev Container, stop takes down every service in the project, not just the one the pane runs in. For a project with a database, cache, and gateway, that is one keystroke stopping six containers instead of one. The confirmation names every container before anything happens, and still proceeds only on an explicit y.
Stop means the whole Compose project
A Compose-based Dev Container is one service among several. Stopping only it left postgres, redis, and everything else running after the user asked to stop the Dev Container. That is also what devcontainer.json asks for: shutdownAction defaults to stopCompose for Compose configs, which is what VS Code does on disconnect.
Project membership comes from the container's own com.docker.compose.project label — the label Compose itself uses — so nothing here re-derives a project name from devcontainer.json.
stop 6 containers for /home/you/workspace/app?
app app_devcontainer-app-1 dc08b7aeca6f
supabase-gateway app_devcontainer-supabase-gateway-1 293672c080bb
gotrue app_devcontainer-gotrue-1 774e6d94d1c3
redis app_devcontainer-redis-1 f33d5de3a11e
postgres app_devcontainer-postgres-1 6cc33c601af0
inbucket app_devcontainer-inbucket-1 348a5d6e757b
[y/N]:
A single-container repository renders exactly as it did before.
Details that matter in practice
- The Dev Container stops first, in its own
docker stopcall, and is waited on — so it releases its database connections before the database goes down. This needs a separate call:docker stop a b cstops the named containers in parallel, and argument order only controls the order results print. docker compose runcontainers are left alone, matchingdocker compose stop. Acompose run --rm app pytestrunning in another pane survives.- An exited Dev Container no longer hides a running project. If the app container exits on its own — a crash, an OOM kill, a stop from another pane — while its services keep running, v0.1.2 reported "no running dev container" and exited 0. Its survivors are now reported and offered for stopping.
- Whether the stop worked is asked of docker, not inferred from
docker stop's output. On timeout the CLI is killed and its output says nothing about what landed, so the most likely partial stop was the one that reported the least. Anything still running is named in the error.
Upgrade
herdr plugin install gambtho/herdr-devcontainer --ref v0.2.0If you prefer the old single-container behavior, stay pinned to --ref v0.1.2.
Full changelog: v0.1.2...v0.2.0
v0.1.2 — find dev containers labelled by VS Code on Windows
Bug-fix release for a discovery defect found on real use.
The bug
stop reported "no running dev container" for a container running in front of the user, and the pane path's ambiguity check was silently checking an empty set.
Discovery matched on one label:
docker ps -a --filter label=devcontainer.local_folder=<repo-root>
Labels are written once, at container creation. VS Code on Windows creates them with local_folder holding the host's UNC view of the WSL path — \\wsl.localhost\Ubuntu\home\you\repo — which no POSIX repository root can equal.
Nothing repairs it afterward. Compose-based dev containers are reused by Compose's own project name, so devcontainer up kept handing back the VS Code-created container while discovery stayed blind to it: the container looked freshly opened by Herdr and then could not be stopped.
The fix
Discovery now also matches devcontainer.config_file, which the Dev Containers CLI resolves from inside WSL and which therefore holds a POSIX path on those same containers. Both keys stay exact-match — reconstructing the UNC form from WSL_DISTRO_NAME was rejected as guessing at how the host renders a path. Docker ANDs repeated --filter label arguments, so this is a second docker ps whose results are unioned and collapsed by container id.
Hardening on the same axis
Several paths could report a container as absent when the answer was simply unknown. All now say so instead:
- An unreadable plugin config or an escaping repo-relative
configvalue silently narrowed the search and reported the empty result as fact. - A
docker pstimeout surfaced asdocker command failed:with no detail. - A listing truncated by a read error, or by the 64 KiB capture cap, parsed cleanly and was indexed as the complete set of containers.
- The two lookups are not atomic, so a container that started between them could be retained in its stale
exitedstate. detectalready knew which config path existed and discarded it, costing an extradocker psagainst a path known to be missing.- The multiple-containers error claimed every id carried
devcontainer.local_folder=<root>— false in exactly the case it most often reports.
Install
herdr plugin install gambtho/herdr-devcontainer --ref v0.1.2Full changelog: v0.1.1...v0.1.2
v0.1.1 — pane directory and container environment
Bug-fix release. Both fixes are in the exec path and both change observable behavior, so this is worth taking if you are on v0.1.0.
Fixed
Panes now open in the directory you were actually in. The working directory was read from the wrapper's own process, but Herdr runs a plugin pane from the plugin root — it has to, since manifest commands are plugin-relative. Every launch therefore looked like an out-of-repo checkout: every pane printed the "current directory is not under …" notice, and panes opened from a subdirectory silently started at the container workspace root. The directory now comes from Herdr's invocation context, and the notice is back to meaning what it says.
Panes now see the environment the container sets up for itself. sh -lc is not the container user's shell, and a login-but-not-interactive shell reads no rc file — so PATH entries and API endpoints written by postCreateCommand and friends were missing, and an agent pointed at a local model proxy by its container's setup script would quietly bypass it. Panes now run the container user's own shell, interactively.
New
repos."<root>".shell— override the shell instead of probing the container's passwd database.repos."<root>".env—KEY=valueassignments passed todocker exec -e, for environment a repository expresses only indevcontainer.json'sremoteEnv.
Behavior worth knowing
- bash is not run as a login shell. It reads
~/.bashrconly when interactive and not a login shell, so-lwould suppress the very file this release exists to load. bash gets-i/-ic; every other known shell keeps-li/-licand the/etc/profilevalues that come with it. - "Known" is a verified list. sh, ash, dash, busybox, zsh, ksh, mksh, pdksh, yash, and fish each accept those combined flags. Anything else is driven with bare
-c, because not every shell takes them —tcsh -licfails with "Unknown option", which would produce a pane that never opens. That fallback is the one case where a command pane is not interactive and no startup file is guaranteed. - rc files run now, and an rc file that changes directory wins.
docker exec -wstill places the shell correctly, but acdin~/.zshrc— some images bake one in — runs afterwards. remoteEnvis still not parsed. Its effective value merges Features and image-label metadata thatdevcontainer upnever reports, so readingdevcontainer.jsonalone would produce a partial environment that reads as authoritative. A pane's environment comes from the image, the shell's startup files, andenv— anything you depend on belongs inenv.- Fallbacks say so. A shell probe that cannot answer prints why rather than silently using
sh, and a context directory that will not resolve is named rather than quietly swapped.
Install this release
herdr plugin install gambtho/herdr-devcontainer --ref v0.1.1Requirements
Unchanged from v0.1.0: Herdr 0.8.0+, Linux or WSL2, Git, Docker, the Dev Containers CLI, and Rust 1.74+ for the install-time build.
Known limitations
Unchanged from v0.1.0, including that a linked worktree checked out outside the main repository directory is not separately mounted, and panes opened there start at the container workspace root.
v0.1.0 — Dev Container panes for Herdr
Superseded by
v0.1.1. Two defects in this release's exec path were found on first real use, so installv0.1.1instead.Two claims below are no longer accurate for the current plugin:
- "Opens an interactive login shell (
sh -l)" — panes now run the container user's own shell, interactively, becausesh -lsources no rc file and so missed thePATHentries and API endpoints a container writes for itself.- "Maps a pane's current directory into
remoteWorkspaceFolderwhen available" — in this release it never was available. The directory was read from the wrapper's own process, which Herdr runs from the plugin root, so every pane opened at the container workspace root and printed an out-of-repo notice.The rest of this text describes
v0.1.0as shipped and is left unchanged.
First public release of a Herdr plugin for opening shell and coding-agent panes
inside a repository's existing Dev Container.
Highlights
- Opens an interactive login shell (
sh -l) inside the container. - Runs a configurable command inside the container; defaults to
claude. - Uses the official Dev Containers CLI and the repository's own
devcontainer.json— no second container format, and no editor required. - Detects both
.devcontainer/devcontainer.jsonand.devcontainer.json, plus
an alternate repo-relative config path. - Uses the main Git worktree as repository and container identity, so linked
worktrees share one container instead of colliding on ports. - Refuses to guess when multiple running containers claim the same repository.
- Serializes concurrent bring-up with a per-repository file lock.
- Maps a pane's current directory into
remoteWorkspaceFolderwhen available,
and says so plainly when it cannot. - Explicit, confirmed stop — only
yoryesproceeds, and the plugin never
runsdocker rm. - Runs host subprocesses as direct argv arrays and reports actionable errors.
Requirements
- Herdr 0.8.0+
- Linux or WSL2
- Git
- Docker with a reachable daemon
- Dev Containers CLI (
npm install -g @devcontainers/cli) - Rust 1.74+ and Cargo, for the install-time build
The committed Cargo.lock is resolved against Rust 1.74 rather than against the
newest published dependencies, and CI verifies that minimum on every change, so
the declared toolchain requirement is the one that actually compiles.
Install this release
herdr plugin install gambtho/herdr-devcontainer --ref v0.1.0Installing from GitHub builds the plugin from source via the manifest's
cargo build --release hook.
Known limitations
- macOS and native Windows are not supported.
- GitHub installation builds from source and requires a Rust toolchain.
- Linked worktrees share the main repository's container; a checkout outside the
main repository directory is not separately mounted, and panes opened there
start at the container workspace root. - The plugin uses its own XDG configuration path rather than Herdr's managed
plugin config directory. - Nothing in the repository parses
herdr-plugin.toml, so manifest validity is
established by installing into a real Herdr, not by the Rust test suite.
Trust
Installing a Herdr plugin runs its build and runtime commands as your user, and
devcontainer up executes repository-controlled Dockerfile and lifecycle code.
This plugin inherits the Dev Containers trust model and is not a security
boundary. Review herdr-plugin.toml and the source before installing.