Files
dotfiles/.agents/skills/add-bootstrap-module/SKILL.md
T
noconnorandClaude Opus 4.8 485e267565 .agents/: add skills for working on this repo
Five skills covering this repo's own conventions: adding a bootstrap
module, adding a CLI to bin/, bumping a pinned version, adding an MCP
server, and verifying a module change.

Lives in .agents/skills/ because opencode discovers that path natively
alongside .opencode/skills/ and .claude/skills/, making it the most
tool-neutral of the three. Distinct from the repo's skills/ tree, which
ships to every covert-gpt user via sync.sh; these stay in the checkout.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 13:10:18 -04:00

72 lines
3.3 KiB
Markdown

---
name: add-bootstrap-module
description: 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.
1. **POSIX `sh`, not bash.** `#!/usr/bin/env sh` + `set -eu`. No `[[`, no
arrays, no `local`. These boxes are RHEL- *and* Debian-family; don't assume
bash is the `/bin/sh`.
2. **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.sh` is the model: it explains that a missing `npx` surfaces
only as a dead MCP server, which is easy to misdiagnose.
3. **Locate the repo without depending on `$PWD`:**
```sh
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
REPO_ROOT="$(dirname -- "$SCRIPT_DIR")"
```
4. **Reuse `lib/`.** `lib/os-detect.sh` for `pkg_install` (handles dnf/yum vs
apt); `lib/fetch.sh` for `fetch_arch`, `have_version`/`mark_version`, and
the `install_*_bin` helpers. Source with a shellcheck directive:
```sh
# shellcheck source=../lib/fetch.sh
. "$REPO_ROOT/lib/fetch.sh"
```
5. **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/` and `ansible/` both guard this way.
6. **Log to stderr** via a `say()` helper, so stdout stays usable.
7. **Prefer `$HOME`.** Everything under `~/.local` survives 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 (`docker/` before `bin/`
so kind's gate sees the daemon; `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/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.