Author SHA1 Message Date
clawbot 1fec3be0e3 REPO_POLICIES: describe script/update-policy in its target's list item
check / check (push) Successful in 28s
The `make update-policy` item now names its script in the form of the
other targets, and the separate paragraph on `script/update-policy`
after the list of scripts with no required target is gone, as the
review at #159 (comment)
asks. `last_modified` is the date of this change.

Model: opus-5-5
2026-11-15 06:42:27 +00:00
clawbot 7389dcbcc1 REPO_POLICIES: apply the wordings from the latest compaction review
Applies the "Acceptable" wording of each of the seven findings at
#159 (comment), as
#159 (comment) says.

Model: opus-5-5
2026-11-15 06:40:29 +00:00
clawbot ebf9475aad REPO_POLICIES: name examples/ in README, correct the lint example's link
As #159 (comment) says.

- `README.md`: Design names `examples/`.
- `prompts/REPO_POLICIES.md`: the sentence linking
  `examples/go-lint-system-libraries.Dockerfile` says the file holds the
  first lines of a lint phase.

Model: opus-5-5
2026-11-15 06:40:29 +00:00
clawbot 62b56a2024 REPO_POLICIES: move the example Dockerfiles into examples/
Each fenced dockerfile block moves byte for byte into its own file
under examples/, and one sentence links it where the block stood.
Phrases that pointed at a block by position now name the file. Both
checklists name the files. Rules keep their wording.

As #159 (comment) says.

Model: opus-5-5
2026-11-15 06:40:29 +00:00
clawbot feeb1d4cb8 REPO_POLICIES: fix the second review's findings on the compaction (#158)
Fixes the seven findings of
#159 (comment), with
the wording each one gives.

- Go key points: "whatever files the mount holds".
- `.dockerignore`: "Such a `.dockerignore` is more dangerous than a
  short file with no secret patterns at all".
- Python: "pipenv checked the hashes of the lockfile's packages".
- Python: "In that step" leads only the two bullets about that step.
  The other four sit under "A Python repository's `script/bootstrap`:".
- Entrypoints: "Three more scripts have no required target:".
- Dockerfile: the two ways a stage installs what its image lacks are
  bulleted again, as on `next`.
- Version: the sentence ends at "stage-scoped", then "It has no
  default."

Model: fable-5-1
2026-11-15 06:40:29 +00:00
clawbot 5cf6e64857 REPO_POLICIES: fix the review findings on the compaction (#158)
Fixes the findings of the review of
#159.

- CI: "The workflow sets these:", so the four settings bind every
  repo's workflow again.
- node and yarn: a stage that needs no yarn copies no `yarn.lock`
  before it runs `script/bootstrap`, which is what the examples do.
- Dockerfile: names the stage to keep last, the one that ships.
- Version: "Without that check" replaces "Otherwise".
- The lists the review named are bulleted again, with the wording on
  `next`. The submodule examples are in their own sentence, as in both
  checklists.

Model: fable-5-1
2026-11-15 06:40:29 +00:00
clawbot ccb49b0f5e Compact REPO_POLICIES.md without losing rules (closes #158)
The rules now sit under headings, the pinning rule first. Each rule that
was stated in several places is stated once. From 1,145 lines and 8,427
words to 1,012 lines and 7,709 words. Code blocks are unchanged, except
that the Makefile copies of the Go and Python test commands are gone:
the Dockerfile examples carry the same commands.

Both checklists name the `.golangci.yml` section.

Model: fable-5-1
2026-11-15 06:40:29 +00:00
10 changed files with 1034 additions and 1102 deletions

No files matched your search

+2 -1
View File
@@ -175,7 +175,8 @@ share, and evolve prompts across projects.
The repository is a collection of Markdown files organized in the `prompts/` The repository is a collection of Markdown files organized in the `prompts/`
subdirectory. Each file contains one or more related prompts or policy subdirectory. Each file contains one or more related prompts or policy
documents. There is no build step or runtime component; the prompts are consumed documents. There is no build step or runtime component; the prompts are consumed
by copying them into other projects or referencing them directly. by copying them into other projects or referencing them directly. `examples/`
holds the example `Dockerfile` files that `prompts/REPO_POLICIES.md` links to.
## Template Repos ## Template Repos
@@ -0,0 +1,8 @@
FROM golangci/golangci-lint@sha256:... AS lint
RUN apt-get update \
&& apt-get install -y --no-install-recommends libvips-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
ARG CACHEBUST
+85
View File
@@ -0,0 +1,85 @@
# In every stage ARG CACHEBUST comes right after the steps that install
# system packages and download Go's modules, or right after FROM in a
# stage with neither, and every step that lints, tests or compiles
# comes after it. script/ passes a new value on every build, which
# reruns every RUN step after it. Docker keeps the layers above it
# until the base image, their own lines or go.mod and go.sum change.
# The steps that compile mount Go's build cache, and golangci-lint run
# also mounts golangci-lint's; both survive from build to build.
# Lint phase
# golangci/golangci-lint:v2.x.x, YYYY-MM-DD
FROM golangci/golangci-lint@sha256:... AS lint
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
ARG CACHEBUST
COPY . .
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/root/.cache/golangci-lint \
golangci-lint run --config .golangci.yml ./...
# Test phase. -race needs cgo and so a C compiler, which the Debian Go
# image ships and the alpine one does not. -count=1 because the mounted
# cache also holds test results, which go test would otherwise replay.
# A first run that timed out gets no rerun, because a rerun would only
# wait for the same hang.
# golang:1.x, YYYY-MM-DD
FROM golang@sha256:... AS test
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
ARG CACHEBUST
COPY . .
RUN --mount=type=cache,target=/root/.cache/go-build \
status=0; \
output=$(go test -count=1 -timeout 90s -race -cover ./... 2>&1) || status=$?; \
printf '%s\n' "$output"; \
test "$status" -eq 0 && exit 0; \
case "$output" in \
*"panic: test timed out"*|*"*** Test killed"*) exit 1 ;; \
esac; \
echo "--- Rerunning with -v for details ---"; \
go test -count=1 -timeout 90s -race -v ./...; \
exit 1
# Build stage. Nothing is wanted from either phase above; the copies
# are what make BuildKit build them first, so nothing after them can
# run unless lint and test passed.
# golang:1.x-alpine, YYYY-MM-DD
FROM golang@sha256:... AS builder
# git comes from the base image's own distribution package index, which
# is trusted, so it needs no version and no hash.
RUN apk add --no-cache git
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
ARG CACHEBUST
COPY --from=lint /src/go.sum /dev/null
COPY --from=test /src/go.sum /dev/null
# A tar-stream context keeps the sender's file owners, which git refuses.
RUN git config --system --add safe.directory /src
COPY . .
# The VERSION build arg when one is given, otherwise
# `git describe --tags --always` on the .git in the build context. With
# .git present, a version that is still empty, dev or unknown fails the
# build: git is missing or could not read the checkout.
ARG VERSION
RUN --mount=type=cache,target=/root/.cache/go-build \
VERSION="${VERSION:-$(git describe --tags --always)}"; \
if [ -e .git ]; then \
case "$VERSION" in ""|dev|unknown) \
echo "version is '$VERSION' although .git is present" >&2; \
exit 1 ;; \
esac; \
fi; \
CGO_ENABLED=0 go build -trimpath \
-ldflags="-s -w -X main.Version=${VERSION}" \
-o /app ./cmd/app/
# Runtime stage, and the last one
FROM alpine@sha256:...
ARG CACHEBUST
COPY --from=builder /app /usr/local/bin/app
ENTRYPOINT ["app"]
+24
View File
@@ -0,0 +1,24 @@
# Test phase. Both pytest runs share one 90-second timeout, so a hang
# uses it once and gets no rerun.
# debian:trixie-slim, YYYY-MM-DD
FROM debian@sha256:... AS test
# Python, pip and venv come from the distribution, which is trusted, so
# they need no version and no hash. make and git are base tools that
# script/bootstrap installs when they are missing. Installed here, they
# stay in their own layer when script/ changes.
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates make git \
python3 python3-venv \
&& rm -rf /var/lib/apt/lists/*
# script/bootstrap installs pipenv in a virtual environment at
# $HOME/.pipenv, and the tests below run that pipenv.
ENV PATH=/root/.pipenv/bin:$PATH
WORKDIR /app
COPY script/ script/
COPY Pipfile Pipfile.lock ./
RUN script/bootstrap
ARG CACHEBUST
COPY . .
RUN timeout 90 sh -c 'pipenv run pytest || { \
echo "--- Rerunning with -v for details ---"; \
pipenv run pytest -v; exit 1; }'
+5 -5
View File
@@ -71,8 +71,8 @@ with your task.
also mounts golangci-lint's also mounts golangci-lint's
(`--mount=type=cache,target=/root/.cache/golangci-lint`), and no step (`--mount=type=cache,target=/root/.cache/golangci-lint`), and no step
mounts anything else; both `go test` runs carry `-count=1`; a first run mounts anything else; both `go test` runs carry `-count=1`; a first run
that timed out gets no rerun, as in the canonical Go `Dockerfile` in that timed out gets no rerun, as in `examples/go.Dockerfile` in the
`REPO_POLICIES.md` `prompts` repo
- [ ] Python: a `test` phase that installs its packages from `Pipfile.lock` does - [ ] Python: a `test` phase that installs its packages from `Pipfile.lock` does
it above `ARG CACHEBUST`, with `COPY script/ script/`, it above `ARG CACHEBUST`, with `COPY script/ script/`,
`COPY Pipfile Pipfile.lock ./` and `RUN script/bootstrap`. When `COPY Pipfile Pipfile.lock ./` and `RUN script/bootstrap`. When
@@ -92,8 +92,8 @@ with your task.
installs no Python, because a step above it already did. `Pipfile` names no installs no Python, because a step above it already did. `Pipfile` names no
`python_version`, because `--deploy` stops when the distribution's Python `python_version`, because `--deploy` stops when the distribution's Python
differs from it. The tests run after `ARG CACHEBUST`, and every other stage differs from it. The tests run after `ARG CACHEBUST`, and every other stage
installs its Python packages after it, as in the Python `test` phase example installs its Python packages after it, as in
in `REPO_POLICIES.md` `examples/python-test-phase.Dockerfile` in the `prompts` repo
- [ ] The gate phases invoke their tools directly, never through `make lint` or - [ ] The gate phases invoke their tools directly, never through `make lint` or
`script/test` — those are themselves a `docker build` and would recurse `script/test` — those are themselves a `docker build` and would recurse
@@ -163,7 +163,7 @@ with your task.
- [ ] Go: `go.mod`, `go.sum`, `.golangci.yml` (fetch from - [ ] Go: `go.mod`, `go.sum`, `.golangci.yml` (fetch from
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml` and, `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 in the same commit, set the lint phase digest to the one named in the
`.golangci.yml` paragraph of `REPO_POLICIES.md`) `.golangci.yml` section of `REPO_POLICIES.md`)
- [ ] JS: `package.json`, `yarn.lock`, `.yarnrc.yml`, `.yarn/releases/`, - [ ] JS: `package.json`, `yarn.lock`, `.yarnrc.yml`, `.yarn/releases/`,
`.gitattributes`, `.prettierrc`, `.prettierignore` (fetch the last two `.gitattributes`, `.prettierrc`, `.prettierignore` (fetch the last two
from `https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierrc` from `https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierrc`
+5 -5
View File
@@ -140,8 +140,8 @@ Template files can be fetched from:
also mounts golangci-lint's also mounts golangci-lint's
(`--mount=type=cache,target=/root/.cache/golangci-lint`), and no step (`--mount=type=cache,target=/root/.cache/golangci-lint`), and no step
mounts anything else; both `go test` runs carry `-count=1`; a first run mounts anything else; both `go test` runs carry `-count=1`; a first run
that timed out gets no rerun, as in the canonical Go `Dockerfile` in that timed out gets no rerun, as in `examples/go.Dockerfile` in the
`REPO_POLICIES.md` `prompts` repo
- Python: a `test` phase that installs its packages from `Pipfile.lock` does - Python: a `test` phase that installs its packages from `Pipfile.lock` does
it above `ARG CACHEBUST`, with `COPY script/ script/`, it above `ARG CACHEBUST`, with `COPY script/ script/`,
`COPY Pipfile Pipfile.lock ./` and `RUN script/bootstrap`. When `COPY Pipfile Pipfile.lock ./` and `RUN script/bootstrap`. When
@@ -162,8 +162,8 @@ Template files can be fetched from:
because a step above it already did. `Pipfile` names no because a step above it already did. `Pipfile` names no
`python_version`, because `--deploy` stops when the distribution's `python_version`, because `--deploy` stops when the distribution's
Python differs from it. The tests run after `ARG CACHEBUST`, and every Python differs from it. The tests run after `ARG CACHEBUST`, and every
other stage installs its Python packages after it, as in the Python other stage installs its Python packages after it, as in
`test` phase example in `REPO_POLICIES.md` `examples/python-test-phase.Dockerfile` in the `prompts` repo
- Server: the final stage builds and runs the application - Server: the final stage builds and runs the application
- Non-server: the final stage brings up the dev environment - Non-server: the final stage brings up the dev environment
@@ -180,7 +180,7 @@ Template files can be fetched from:
- [ ] Go: `go mod init sneak.berlin/go/<name>`, `.golangci.yml` (fetch from - [ ] Go: `go mod init sneak.berlin/go/<name>`, `.golangci.yml` (fetch from
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml` and, `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 in the same commit, set the lint phase digest to the one named in the
`.golangci.yml` paragraph of `REPO_POLICIES.md`) `.golangci.yml` section of `REPO_POLICIES.md`)
- [ ] JS, or any repository that runs prettier through yarn: make the first - [ ] JS, or any repository that runs prettier through yarn: make the first
`yarn.lock` with the steps below. `script/bootstrap` installs no yarn `yarn.lock` with the steps below. `script/bootstrap` installs no yarn
until `yarn.lock` exists, so run them with any distribution's node and until `yarn.lock` exists, so run them with any distribution's node and
+897 -1083
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -8,8 +8,8 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() { main() {
cd "$ROOT" cd "$ROOT"
hook=".git/hooks/pre-commit" hook=".git/hooks/pre-commit"
printf '#!/bin/sh\nset -e\nscript/precommit\n' > "$hook" printf '#!/bin/sh\nset -e\nscript/precommit\n' > .git/hooks/pre-commit
chmod +x "$hook" chmod +x .git/hooks/pre-commit
echo "pre-commit hook installed: runs script/precommit" echo "pre-commit hook installed: runs script/precommit"
} }
+3 -3
View File
@@ -1,11 +1,11 @@
#!/bin/sh #!/bin/sh
# script/lint: run the linter. Linting is a phase of the Dockerfile and # script/lint: run the linter. Linting is a phase of the Dockerfile and
# this builds that phase; the linter is never installed or run on # this builds that phase alone; the linter is never installed or run on
# a developer host, where a shared result cache and a host-global lock # a developer host, where a shared result cache and a host-global lock
# make its answer untrustworthy. # make its answer untrustworthy.
# #
# --target builds the lint phase and the stages it depends on, nothing # The phase is not the last stage in the file, so it is built only when
# else. A new CACHEBUST value reruns every RUN step after # --target names it. A new CACHEBUST value reruns every RUN step after
# the ARG CACHEBUST line, since a cached lint layer is a lint that did # the ARG CACHEBUST line, since a cached lint layer is a lint that did
# not run; unlike --no-cache, it keeps the layers above that line and # not run; unlike --no-cache, it keeps the layers above that line and
# the cache mounts. This relies on every stage of the Dockerfile # the cache mounts. This relies on every stage of the Dockerfile
+3 -3
View File
@@ -1,8 +1,8 @@
#!/bin/sh #!/bin/sh
# script/test: run the test suite. Testing is a phase of the Dockerfile # script/test: run the test suite. Testing is a phase of the Dockerfile
# and this builds that phase, on the same terms as script/lint: # and this builds that phase alone, on the same terms as script/lint:
# --target so that only the test phase and the stages it depends on are # --target because a phase that is not the last stage is built only when
# built, and a new CACHEBUST value because a cached test layer is a test # named, and a new CACHEBUST value because a cached test layer is a test
# that did not run; unlike --no-cache, it keeps the layers above the ARG # that did not run; unlike --no-cache, it keeps the layers above the ARG
# CACHEBUST line and the cache mounts. This relies on every stage of the # CACHEBUST line and the cache mounts. This relies on every stage of the
# Dockerfile declaring ARG CACHEBUST before every step that lints, tests # Dockerfile declaring ARG CACHEBUST before every step that lints, tests