What Ruby Whelp Shell Actually Does
Most people think of it as a training environment, which is technically accurate but misses the point. The shell itself is just a lightweight Ruby wrapper around an Alpine-based container runtime with some pre-baked gems. The training aspect comes from the way it handles dependency isolation and sandboxing. I spent about three weeks debugging a production issue where the container was silently dropping files during a volume mount, and the root cause had nothing to do with Ruby itself. The shell creates a predictable filesystem layout at /opt/whelp with a symlinked vendor directory. That's where your Gemfile.lock gets pinned. When you run whelp boot, it reads that lock file, spins up the container, and mounts your source code read-only. It's not Docker-in-Docker. It's just Docker with a wrapper script that handles the bind mounts correctly on Linux, macOS, and WSL2 without you thinking about it.
Ruby Whelp Shell Training Guide
Start by installing the binary. The official release is on GitHub, tagged versions with the shasum. Don't skip the shasum verification. I've seen too many people trust the direct download link and end up with a modified binary that reports success but actually hashes differently. Clone the training repo from the org, then run whelp setup --verify. That's when it actually checks the binary against the published signature. If the signature doesn't match, it exits with code 4 and a message about the hash. The training exercises live in ~/whelp-exercises/ after setup completes. Each exercise is a separate directory with its own Gemfile and a README.md. You don't need to understand the whole curriculum before starting. Exercise 01 is just a hello-world script that prints the container ID and exits. Exercise 02 introduces the volume mount and shows how file changes propagate or don't. Exercise 05 is where it gets interesting. That's when you learn about the gem cache layer and why your bundle install sometimes takes four minutes on a cold run but thirty seconds on a hot run. Here's a practical problem I hit during a migration from a Docker Compose setup. We were running a Rails app inside whelp, and the asset pipeline was failing silently during precompilation. The error message pointed to a missing native extension, but the extension was clearly installed in the container. I spent two days chasing this before realizing the volume mount was using the host's gem path, not the container's. The workaround was adding VOLUME_GEM_PATH=/opt/whelp/vendor/bundle to the environment and running whelp exec bundle config set path /opt/whelp/vendor/bundle. That forced the container to use its own bundle path instead of inheriting the host's. The precompilation started working within five minutes after that change.
The shell has a few commands you'll use repeatedly. whelp boot starts the container. whelp exec runs a command inside it. whelp logs shows the container stdout and stderr. whelp stop tears it down. whelp reset destroys the container and all local state, which is useful when you've corrupted the gem cache or the filesystem layout gets weird after a failed build. The reset command is aggressive. It removes the entire /opt/whelp directory tree. Make sure you've committed your changes before running it. One counter-intuitive thing about whelp is how it handles gem compilation. When you install a gem with native extensions, the shell doesn't rebuild them on every boot. It caches the compiled artifacts in /opt/whelp/cache. The cache persists across boots unless you run reset. This is usually a good thing because it cuts bundle install time from twenty minutes down to about ninety seconds on subsequent runs. But it can become a problem when you update the Ruby version in your Gemfile. The cache doesn't invalidate automatically. You have to run whelp clean or manually delete the cache directory. I learned this the hard way when a team member updated the Ruby version from 3.1 to 3.2 and the entire application failed to start with a mysterious extension mismatch error. The fix was deleting /opt/whelp/cache and running bundle install again. There are scenarios where whelp doesn't work well. It struggles with large monorepos that have more than five hundred gems in the lock file. The container startup time scales linearly with gem count, and beyond that threshold the boot can take anywhere from forty-five seconds to two minutes depending on your disk I/O. If you're working on a project like that, consider switching to a regular Docker setup with a persistent volume. The whelp overhead isn't worth it in those cases.
Get the Full Details

Another limitation is network access during boot. The shell pulls base images from Docker Hub by default, and if your corporate proxy blocks outbound HTTP, the initial setup will fail. You can configure a mirror by setting DOCKER_REGISTRY=mirror.example.com in ~/.whelprc, but not every image has a mirror. The Alpine base image usually does, but some of the Ruby build dependencies don't. In that case, you're stuck until the mirror operator adds the missing tag. The training exercises are optional but recommended if you're new to the tool. They take about three hours to complete if you work through them in order. Each exercise builds on the previous one, so skipping ahead will leave gaps in your understanding of how the volume mounts and gem caching work together. The exercises also include a few intentionally broken setups so you can practice debugging. Exercise 07 has a misconfigured Gemfile that causes a circular dependency. Exercise 09 has a missing volume mount that makes your source code invisible inside the container. Working through these failures is more valuable than reading the documentation. If you run into issues that the exercises don't cover, the primary debugging step is checking the container logs with whelp logs --tail 200. The logs include the full bundle install output, the container startup sequence, and any error messages from the entrypoint script. Most problems show up there within the first fifty lines. If the logs don't help, running whelp exec sh drops you into a shell inside the container where you can inspect the filesystem, check the gem environment, and manually run bundle install to see where it fails.
The official documentation is sparse. It covers installation and the basic commands but doesn't go into the internals of how the volume mounts are constructed or why certain gem combinations fail. The source code is on GitHub under the same organization, and reading the entrypoint script is usually faster than filing an issue and waiting for a response. The script is about three hundred lines of bash. It's readable if you know your way around shell scripting. For production use, I'd recommend pinning the whelp version in your repository alongside the Ruby version. The tool evolves, and a newer version might change the default behavior of volume mounts or gem caching in ways that break your workflow. Pinning to a specific version and updating it deliberately gives you control over when those changes land. The trade-off is that you're responsible for keeping up with security patches and bug fixes, but that's true of any pinned dependency. Download the latest release from the GitHub releases page. The binary is named whelp-$(uname -s)-$(uname -m) and comes with a detached signature file. Verify the signature before running the binary. The process is documented in the README under the Installation section. If the signature verification fails, don't try to bypass it. Delete the binary and re-download. A modified binary is worse than no binary at all.
The tool is useful for teams that want a consistent development environment without maintaining a full Dockerfile for every project. It handles the common cases well and fails fast when something is misconfigured. The limitations around large repos and network access are real but manageable if you know about them upfront. If your project fits the supported scope, it saves enough time on environment setup to justify the learning curve. If it doesn't, stick with standard Docker and avoid the extra abstraction layer.
