Files
prompts/prompts/NEW_REPO_CHECKLIST.md
clawbot 417f142a9f
Some checks failed
check / check (push) Has been cancelled
Bust the Docker check-layer cache with a per-invocation CHECK_EPOCH (closes #26)
script/cibuild was a plain `docker build .`, and the Dockerfile does
`COPY . .` followed by `RUN make check`. Docker invalidates a COPY layer
only when the copied content changes, so on an unchanged tree the check
layer was served from cache, the suite never ran, and the build still
exited 0. Measured here: run 1 took 18.5s and ran the suite; run 2 on a
byte-identical tree took 0.286s with `RUN make check` CACHED.

script/cibuild and script/docker now assign a per-invocation nonce on its
own line and pass it as --build-arg CHECK_EPOCH. The Dockerfile declares
ARG CHECK_EPOCH, guards it with `[ -n "$CHECK_EPOCH" ] || exit 1`, and
expands it into the check command. Post-fix, two consecutive runs both
execute make check (17.4s / 8.1s) with `RUN script/bootstrap` still
CACHED, so dependency layers are untouched and the build ceiling is not
at risk.

The guard is what makes a bare `docker build .` — the command
REPO_POLICIES named verbatim — fail closed rather than reuse the empty
and therefore stable cache key; verified failing in 0.455s. Holding the
epoch constant restores the false green (run 2 fully CACHED), which pins
the varying value as the operative mechanism rather than a coincidence.

Because the guard references $CHECK_EPOCH it is itself value-keyed:
BuildKit renders the epoch into that layer's description and re-runs the
layer when the value changes. Each stage therefore has two independent
invalidation points, the guard and the expansion, and the guard always
precedes the check RUN. Both are kept and the prose now records this;
the expansion remains defence in depth and is what puts the epoch in the
build log.

The false guarantee was org-canonical text in more than one document, so
it is corrected everywhere it appeared rather than only where the issue
first found it. REPO_POLICIES.md carried it in two places, and its Go
multistage template had check steps in two stages; ARG is stage-scoped,
so both stages get the treatment or the fleet inherits the half-fixed
shape. CODE_STYLEGUIDE_GO.md restated the guarantee for the bare command
this change makes fail closed. NEW_REPO_CHECKLIST.md specified the
pre-fix script/cibuild verbatim, so every new repo would have been born
with the false green, and EXISTING_REPO_CHECKLIST.md ended on a
`docker build` acceptance item that the guard makes unsatisfiable by
design — an agent working that checklist would have been led to delete
the guard to tick the last box. Both checklists' Dockerfile criteria were
also satisfiable by a Dockerfile whose check layers are still frozen, and
now require the ARG and guard in every check-running stage.
2026-08-09 15:00:49 +00:00

5.5 KiB

title, last_modified
title last_modified
New Repo Checklist 2026-08-09

Use this checklist when creating a new repository from scratch. Follow the steps in order. Full policies are at https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md.

Template files can be fetched from: https://git.eeqj.de/sneak/prompts/raw/branch/main/<path>

1. Initialize

  • git init
  • Ask the user for the license (MIT, GPL, or WTFPL)

2. First Commit (README only)

  • Create README.md with all required sections:
    • Description: name, purpose, category, license, author
    • Getting Started: copy-pasteable code block
    • Rationale: why does this exist?
    • Design: how is it structured?
    • TODO: initial task list
    • License: matches chosen license
    • Author: @sneak
  • git add README.md && git commit

3. Scaffolding (feature branch)

  • git checkout -b initial-scaffolding

Fetch Template Files

  • .gitignore — fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore, extend for language-specific artifacts
  • .editorconfig — fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig
  • Makefile — fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/Makefile, adapt targets for the project's language and tools
  • For JS/docs repos: .prettierrc and .prettierignore — fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierrc and https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierignore

Create Project Files

  • LICENSE file matching the chosen license
  • REPO_POLICIES.md — fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md
  • Dockerfile and .dockerignore — fetch .dockerignore from https://git.eeqj.de/sneak/prompts/raw/branch/main/.dockerignore
    • All Dockerfiles must run make check as a build step, and every stage containing a check-running RUN must declare ARG CHECK_EPOCH with the RUN [ -n "$CHECK_EPOCH" ] || exit 1 guard immediately below it — see the CHECK_EPOCH rule in REPO_POLICIES.md. Without them the check layer is served from cache on an unchanged tree and the build reports a green it never ran.
    • Server: also builds and runs the application
    • Non-server: brings up dev environment and runs make check
    • Image pinned by sha256 hash with version/date comment
  • Gitea Actions workflow at .gitea/workflows/check.yml that runs script/cibuild on push — reference https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml
  • Language-specific:
    • Go: go mod init sneak.berlin/go/<name>, .golangci.yml (fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml)
    • JS: yarn init, yarn add --dev prettier
    • Python: pyproject.toml

Configure script/ Entrypoints and Makefile

Implementations live in script/ (scripts-to-rule-them-all); Makefile targets are thin shims calling them. Model scripts: https://git.eeqj.de/sneak/prompts/raw/branch/main/script/<name>

  • scripts are POSIX sh (#!/bin/sh, set -eu, no bashisms) so they run on alpine images without bash
  • script/bootstrap / make bootstrap — installs all dependencies, idempotently, assuming nothing (pkg manager detection nix/apt/brew/apk; node used if present, else pinned version via nvm from a hash-verified archive; pinned yarn via corepack); Dockerfile runs it instead of inline installs
  • script/setup / make setup — readies a fresh clone: runs bootstrap, then install-precommit, plus repo-specific init
  • script/test / make test — runs real tests, not a no-op (30-second timeout)
  • script/lint / make lint — runs linter
  • script/fmt / make fmt — formats code (writes)
  • script/fmt-check / make fmt-check — checks formatting (read-only)
  • script/check / make check — runs test, lint, fmt-check; must not modify files
  • script/projectname — outputs the project name (used by script/docker for the image tag)
  • script/docker / make docker — builds Docker image, tagged via script/projectname (byte-identical across repos); assigns epoch="$(date +%s%N)$$" on its own line and passes --build-arg CHECK_EPOCH="$epoch"
  • script/cibuild — cd to repo root, assign epoch="$(date +%s%N)$$" on its own line, then run docker build --build-arg CHECK_EPOCH="$epoch" . (what CI runs). The build arg is mandatory: see the CHECK_EPOCH rule in REPO_POLICIES.md for why each element is load-bearing. A bare docker build . fails closed by design.
  • script/precommit — called by the pre-commit hook; runs script/check
  • script/install-precommit — installs the pre-commit hook that runs script/precommit
  • make hooks — shims to script/install-precommit
  • README Entrypoints section documents the scripts and links the standard

4. Verify

  • make check passes
  • make docker succeeds
  • No secrets in repo
  • No mutable image/package references
  • No unnecessary files in repo root
  • All dates written as YYYY-MM-DD

5. Merge and Set Up

  • Commit, merge to main
  • make hooks to install pre-commit hook
  • Add remote and push
  • Verify main passes make check