Files
prompts/prompts/NEW_REPO_CHECKLIST.md
T
clawbot 5de98c404e
check / check (push) Waiting to run
Keep each submodule's git config out of the build context (closes #75)
The canonical `.dockerignore` kept out `.git/config`, which can hold a credential, but not the `config` in each submodule's git directory under `.git/modules/`, nested again for a submodule's own submodules. It now also lists `.git/modules/**/config`, with one sentence in the comment above; `prompts/REPO_POLICIES.md` and both checklists say so in the same words.

The pattern stays under `.git/modules/` because `.git/**/config` would also drop a branch or tag named `config`, which `git describe` may need.

Known gap: a submodule whose name has a `config` path segment loses its whole git directory, so Go's version stamping fails the build loudly; tracked separately.

Model: opus-5-5
2026-10-04 05:31:51 +02:00

9.3 KiB

title, last_modified
title last_modified
New Repo Checklist 2026-10-04

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. Extensions are written to .gitignore's own semantics, where an unanchored pattern already matches at every depth: never add a **/ prefix here, which is a .dockerignore form. The canonical file already carries .claude/ so agent worktrees cannot be committed by accident.
  • .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
    • Extend .dockerignore with the repo's own host-built artifacts, giving every depth-independent pattern a **/ prefix — but write a repo-root binary anchored, /myapp and never **/myapp, which would also match cmd/myapp/ and delete the package directory. Do not transplant .gitignore's patterns: .dockerignore anchors an unprefixed pattern at the context root, so the copied form leaves config/.env in the build context while reading as solved. The canonical file's .claude entry is anchored for the same reason as a repo-root binary; leave it that way, but note that it only covers agents running at the repo root — if this repo will run them in subdirectories, services/api/.claude/ needs its own anchored entry.
    • If the image embeds a version in a binary: .dockerignore lets .git into the build context. It keeps out .git/config and each submodule's config under .git/modules/ at any depth (.git/modules/**/config), which git describe does not need and which can hold a credential: a password in a remote URL, or the token the CI checkout step stores there. The stage that compiles has git (the Debian Go image has it; an alpine one needs apk add --no-cache git) and takes the version from the VERSION build argument when one is given, otherwise from git describe --tags --always. That gives the tag on a tagged commit; on a later commit, the tag, the number of commits since it and the short commit (v1.2.3-4-gabc1234); and the short commit when no tag is reachable. The stage that compiles also marks its working directory safe for git (git config --system --add safe.directory /src): a context sent as a tar stream keeps the sender's file owners, and git refuses a checkout owned by another user, so the version would come out empty. ARG VERSION has no default, and the build fails if the context carries .git and the version still comes out empty, dev or unknown. A plain docker build . with no build arguments must succeed; a Dockerfile that refuses an empty build argument drops that refusal and keeps the argument.
    • The Dockerfile carries a lint phase and a test phase, each invoking its tool directly rather than through make or script/, and the final stage carries a COPY --from= of a harmless file from each so the image cannot be built unless both passed. Keep the final stage last: a stage nothing depends on is built only when --target names it.
    • Server: the final stage builds and runs the application
    • Non-server: the final stage brings up the dev environment
    • 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 and, in the same commit, set the lint phase digest to the one named in the .golangci.yml paragraph of REPO_POLICIES.md)
    • 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 — docker build --no-cache --target test ., tagged; the phase runs real tests, not a no-op (90-second timeout, 60-second hard cap on wall time)
  • script/lint / make lint — docker build --no-cache --target lint ., tagged. No lint verdict may come from a host invocation of the linter.
  • script/fmt / make fmt — formats code (writes; native, never in a container)
  • script/fmt-check / make fmt-check — checks formatting (read-only; native)
  • 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); --no-cache, plus the version as a build arg
  • script/cibuild — cd to repo root, run script/bootstrap, run script/check, then docker build --no-cache --build-arg VERSION="$version" . (what CI runs). The bootstrap is required: CI checks out and runs this alone, and script/fmt-check runs the formatter on the host.
  • script/fmt and script/fmt-check source nvm for the pinned node version before invoking yarn, as script/bootstrap's own install step does. script/bootstrap leaves the node and yarn it installs off the PATH of the shell that called it, so a bare yarn exits 127 on a runner carrying nothing but docker and git.
  • Every docker build in script/ is tagged, so no invocation leaves a dangling image behind
  • 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
  • script/cibuild succeeds in a fresh clone on a host carrying nothing but docker and git, with no node or yarn on PATH, which is what CI has, and demonstrably executed the checks — a sub-second build, or CACHED on a gate layer, means nothing ran
  • Plant a lint violation and confirm both make lint and a plain docker build . fail on it; revert. A plain build that passes proves the final stage is missing its COPY --from= edge to the gate phases.
  • No secrets in repo, and none in the build context: enumerate a probe image rather than reading .dockerignore
  • 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