Installing Docker Engine is a host/image decision, not a per-user environment one. In Coder workspaces (unprivileged pods, no systemd) the module ran get.docker.com on every start for a daemon that can never run there. Where Docker is wanted, install it on the host or bake it into the image. Also drops the zshrc newgrp-docker hook that existed only for this module's group change, and the docs/skills references to docker/. docker-rootless-cgroup/ (configures Kasm's existing rootless daemon) and bin/'s kind gate (detects a daemon) stay. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3.3 KiB
name, description
| name | description |
|---|---|
| add-bootstrap-module | Use when adding a new top-level module to this dotfiles repo (a new directory with an install.sh that bootstrap.sh runs) — e.g. installing a new runtime, configuring a new service, or dropping a new managed rc file. Covers the module contract, ordering in bootstrap.sh, and the README entry. |
Adding a bootstrap module
A module is a top-level directory with an install.sh that bootstrap runs. It
must be safe to run standalone and to re-run on an already-configured box.
The contract
Every module's install.sh satisfies all of these. Copy the shape from
node/install.sh — it is the newest and cleanest example.
- POSIX
sh, not bash.#!/usr/bin/env sh+set -eu. No[[, no arrays, nolocal. These boxes are RHEL- and Debian-family; don't assume bash is the/bin/sh. - A
WHY:header comment. Not what the script does — the code says that. Explain the failure it prevents or the constraint that forced the design.node/install.shis the model: it explains that a missingnpxsurfaces only as a dead MCP server, which is easy to misdiagnose. - Locate the repo without depending on
$PWD:SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" REPO_ROOT="$(dirname -- "$SCRIPT_DIR")" - Reuse
lib/.lib/os-detect.shforpkg_install(handles dnf/yum vs apt);lib/fetch.shforfetch_arch,have_version/mark_version, and theinstall_*_binhelpers. Source with a shellcheck directive:# shellcheck source=../lib/fetch.sh . "$REPO_ROOT/lib/fetch.sh" - Idempotent, and it verifies rather than assumes. Check the tool runs,
not just that the file exists — a Kasm redeploy can leave a present-but-
broken tree behind.
node/andansible/both guard this way. - Log to stderr via a
say()helper, so stdout stays usable. - Prefer
$HOME. Everything under~/.localsurvives a Kasm redeploy (which wipes/but keeps$HOME) and needs no sudo. If the module must use sudo, say so in its header comment and in the README — the repo tracks which modules do.
Wiring it up
bootstrap.sh — add the call. Order is load-bearing and each existing
out-of-order entry carries a comment explaining why (secrets/ after bin/
because it needs op; docker-rootless-cgroup/ last because it needs the
rootless daemon already up). If your module has an ordering
constraint, add it with a comment; if it doesn't, append it near related
modules.
README.md — add a bullet to the ## Modules list. Match the existing
voice: what it installs, where it puts it, whether it uses sudo, and any
host it no-ops on.
~/.zshrc.local — if the module reads a secret or per-machine value, add
the variable to zsh/zshrc.local.example and to the README's variable list.
Never commit the value itself.
Non-systemd hosts
Kasm has no systemd. Anything that would systemctl enable must degrade
gracefully — see docker-rootless-cgroup/install.sh, which detects the situation and no-ops
rather than failing the whole bootstrap run.
Before you're done
Run the verify-module skill. At minimum: shellcheck, run standalone, then
run a second time and confirm the output says "already present" rather than
redoing the work.