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

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.

  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:
    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:
    # 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.