This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Idempotent macOS script that creates /etc/resolver/ overrides for archive.today and its mirror domains, routing them through a trusted DNS nameserver (Google DNS 8.8.8.8) to bypass Cloudflare 1.1.1.1 blocks. Single-file Bash project — install.sh is the entire codebase.
# Lint (matches CI)
shellcheck --severity=warning install.sh
# Syntax check
bash -n install.sh
# Dry-run (requires macOS; no root needed)
sudo ./install.sh --dry-run --no-fetch
# Update mirrors from Wikipedia (no root)
./install.sh --update-mirrors --dry-run
# Install resolver files
sudo ./install.sh
# Uninstall
sudo ./install.sh --uninstallSingle script (install.sh) with two modes:
--update-mirrors: Fetches Wikipedia API, extracts<li>archive.TLD</li>from the infobox, rewritesmirrors.txt. No root needed.- Default (install): Reads
mirrors.txt(fetched from GitHub, or local with--no-fetch), writes/etc/resolver/archive.todaywith the nameserver, symlinks all other mirrors to that file, removes stale entries via manifest at/etc/resolver/.archive-resolver.
Key design: Mirror symlinks point to the filename archive.today (relative, not absolute path) so changing the nameserver only requires updating one file.
mirrors.txt is auto-updated by CI, not a static canonical list. The update-mirrors.yml workflow runs monthly, compares sorted sets (order-insensitive), and opens a PR if domains changed.
- Bump
SCRIPT_VERSIONininstall.sh - Push on a release branch, merge to main
- Tag
vMAJOR.MINOR.PATCHon main — must matchSCRIPT_VERSION release.ymlcreates GitHub release with tarball + individual assets
- ci.yml: bash syntax, mirrors.txt format validation, Linux dry-run (stubs out Darwin check). ShellCheck is not in CI — it runs locally via the global
shell-lint-fixpre-commit hook (~/.config/pre-commit/config.yaml), so every authorized commit is already linted before push. - release.yml: Validates tag matches
SCRIPT_VERSION, lints, publishes release - update-mirrors.yml: Monthly Wikipedia scrape, opens PR if mirror set changed
- All log functions (
info/success/warn/error) write to stderr so$()captures work correctly MANAGED_MARKERcomment in resolver files marks them as script-owned- Comparison of mirror lists is set-based (sorted), not order-based
- Quad9 (9.9.9.9) is blocked by archive.today — do not use as example nameserver
- Script requires GNU Bash features (
mapfile,set -euo pipefail)
Auto-generated by headroom learn on 2026-04-07 — do not edit manually
~2,000 tokens/session saved
- A global pre-commit config at
/Users/andrewrich/.config/pre-commit/config.yamlruns on every commit, includingshellcheck(with--severity=warning) on shell scripts and YAML linting on GitHub Actions workflows. - Always run
shellcheck --severity=warning <script>and validate YAML files before attemptinggit committo avoid repeated failed commit attempts.
~1,500 tokens/session saved
- Merging PRs via
gh pr mergerequires a local merge-lock authorization first: run~/.claude/hooks/merge-lock.sh authorize <PR#> "<title>"before callinggh pr merge. - Do not attempt
gh pr mergewithout user approval and the lock in place; the hook will block it with an error.
~1,200 tokens/session saved
- Always run
bash -n <script>(syntax check) andshellcheck --severity=warning <script>before committing any shell script changes. - Fix all
shellcheckwarnings (not just errors) — unused variables, quoting issues, etc. — before committing.
~500 tokens/session saved
- Branch naming:
claude/feature-<description>-<YYYYMMDD>andclaude/release-<version>-<YYYYMMDD>. - Releases follow a branch-based flow: create
claude/release-X.Y.Z-<date>branch, bump version ininstall.sh, push PR, merge, then tagvX.Y.Zonmain. - GitHub Actions
release.ymlworkflow handles the release after the tag is pushed.
~400 tokens/session saved
- Direct
WebFetchtoen.wikipedia.orgreturns 403. Use the MediaWiki API:curl 'https://en.wikipedia.org/w/api.php?action=parse&page=<PageName>&prop=text&format=json'.
~400 tokens/session saved
- DNS resolver overrides go under
/etc/resolver/as per-domain files. - To flush DNS cache on macOS (including macOS 26+):
sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder. Both commands are required and still valid as of macOS 26.
~300 tokens/session saved
- Do NOT include
curl | bashor equivalent "run directly without cloning" installation patterns in README or documentation — the user explicitly rejects this as a security anti-pattern.