This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
A monorepo of independent utility modules. Each top-level directory (installer/, append-files/, secrets-sanitizer/, update-dns-a-record/, validate-path/) is a self-contained module with its own README.md, entry script, and — if installable — an install.yml. Modules do not share code; the only cross-module contract is the installer protocol below.
installer/install.sh is the stable public interface of this repo. Users invoke it as:
curl -sSL https://raw.githubusercontent.com/descoped/script-utils/master/installer/install.sh | bash -s -- <module_name>It then:
- Downloads
<module_name>/checksums.txt— the trust anchor. Missing checksums abort the install unlessALLOW_UNVERIFIED=1is set (loud warning path). - Downloads
<module_name>/install.ymland verifies it against the checksums file before parsing (the manifest drives what gets installed, so it has to be authenticated first). - Parses the YAML with hand-rolled bash regex (not a real YAML parser — see REQUIREMENTS §7). The supported grammar is a flat list of
- file:entries with optionalexecutable,create-symlink,destinationkeys. Do not expand this surface without switching to a real parser. - Writes an installation plan to a pipe-delimited temp file, prompts
/dev/ttyfor confirmation (bypassable withCONFIRM=1), then downloads each file to$INSTALL_DIR(default$HOME/bin), verifying each against checksums beforechmod +x.destinationentries land under$INSTALL_DIR/.<module>/<destination>/.
Configurable via env: INSTALL_DIR, CONFIRM, SCRIPT_UTILS_REF (commit SHA or branch for reproducible installs — the repo doesn't tag), SCRIPT_UTILS_OWNER, SCRIPT_UTILS_REPO, ALLOW_UNVERIFIED.
Breaking this contract (changing CLI args, YAML keys, target paths, env var names) requires a CHANGELOG.md entry in the same commit per REQUIREMENTS §9. A new installable module needs both install.yml and checksums.txt at the module root — regenerate checksums in the same commit that edits any installable file:
cd <module>/
shasum -a 256 *.sh *.py README.md install.yml > checksums.txtREQUIREMENTS.md is not aspirational — it's a merge blocker. Read it before changing any .sh file. The load-bearing rules:
- §1 Bash 4.x, shebang
#!/bin/bash. Documentation must say| bash -s --, never| sh -s --(several existing READMEs still showsh— these are known gaps). - §2 Every
.shpassesshellcheck --severity=style. Every script starts withset -euo pipefailunless explicitly justified. Use: > file, never bare> file. Everyreaduses-r. - §3 Integrity verification — any script that downloads code for execution must verify SHA-256 before
chmod +x/bash/source.installer/install.shcurrently violates this (known gap in REQUIREMENTS appendix); do not propagate the pattern to new code. - §4 Docs parity — every flag/env var/positional arg in code appears in the README, and vice versa. When you change one, change the other in the same commit.
- §6 Idempotency — state-changing scripts must be re-runnable. Check
[ -e ]/[ -L ]before creating; remove symlinks before recreating. - §7 Interactive prompts read from
/dev/ttyso the script works undercurl | bash. Defaults go inreadonlyblock at the top.
Bash wrapper + Python implementation. The .sh script does Python version gate, dependency install, and arg forwarding; the .py does the work.
append-files.shdetectsuv(via[project]inpyproject.toml) and switchespip3 install→uv pip install. Required packages:click pyperclip tqdm pyyaml.append-files.pydynamically loadsextract-code-signatures.pyviaimportlib.utilbecause of the hyphen in the filename. The transform feature (IDL/JSON output) degrades gracefully if that file is missing.secrets-sanitizeris macOS-only — usespbpaste/pbcopydirectly in the wrapper. Don't add Linux support without reworking the clipboard layer.
Standalone root-only script for Route53 dynamic DNS via cron. No installer integration — users clone and edit PROFILE/HOSTED_ZONE_ID/HOSTNAME inline. Depends on aws CLI and jq.
Pure bash path diagnostics. validate-path.sh is trivial; analyze-path.sh and analyze-path-bash*.sh parse shell rc files. Not wired into the installer.
# Full repo lint sweep (REQUIREMENTS §2 / §10)
find . -name '*.sh' -print0 | xargs -0 shellcheck --severity=style
find . -name '*.sh' -print0 | xargs -0 -I{} bash -n {}
# Per-module smoke test
./secrets-sanitizer/test-secrets-sanitizer.sh # the only existing test harnessThere is no CI config checked in and no package-level test runner — test-secrets-sanitizer.sh is the only executable test suite.