1 Commits
Author SHA1 Message Date
sneak 30e13d73bb Say which Dockerfile stages run script/bootstrap (closes #90)
check / check (push) Waiting to run
The bullet in `prompts/REPO_POLICIES.md` that requires a `Dockerfile` said every Dockerfile installs its prerequisites by running `script/bootstrap`, while the canonical Go `Dockerfile` never runs it: its gate phases use their pinned images as they are and its build stage installs `git` inline.

The bullet now says the gate phases and the build stage take their tools from their pinned base images and install only what those images lack, and that the development environment stage, the final stage of a non-server repo, runs `script/bootstrap`. The new repo checklist says the same.

Model: opus-5-5
2026-10-04 09:04:57 +00:00
5 changed files with 32 additions and 71 deletions
+3 -10
View File
@@ -18,16 +18,9 @@
# does not need .git/config; that file can hold a credential, such as a
# password in a remote URL or the token the CI checkout step stores there.
# Each submodule keeps a config with the same exposure in its git directory
# under .git/modules/, nested again for a submodule's own submodules, or in
# its own .git directory when it keeps one.
# KNOWN GAP: a submodule whose name has a `config` segment (`config`,
# `deploy/config`, `config/lib`) loses its whole git directory, because
# `**/.git/modules/**/config` also matches that segment's directory
# under .git/modules/. Go's version stamping then fails the build;
# nothing leaks. Name such a submodule without that segment:
# `git submodule add --name`.
**/.git/config
**/.git/modules/**/config
# under .git/modules/, nested again for a submodule's own submodules.
.git/config
.git/modules/**/config
# Agent scratch: one full checkout of the repo per in-flight agent.
# Anchored because it occurs once where agents run at the repo root.
+6 -15
View File
@@ -21,21 +21,12 @@ fmt-check, and commit.
# Completed Steps
- 2026-10-04: The canonical `.dockerignore` now also keeps out the git `config`
of a submodule that keeps its own `.git` directory, which still reached the
image (issue 88): both git patterns now carry the `**/` prefix. A submodule
whose name has a `config` segment (`config`, `deploy/config`, `config/lib`)
still loses its whole git directory, so Go's version stamping fails the build;
the file records this as a `KNOWN GAP:` with the remedy,
`git submodule add --name`. Closing it would take a wildcard re-include, which
makes BuildKit walk every excluded directory, such as `node_modules`, on every
build. `REPO_POLICIES.md` and both checklists say so in the same words.
- 2026-10-04: The note under the canonical Go `Dockerfile` example in
`REPO_POLICIES.md` now installs lint-phase system libraries with `apt-get`
under their Debian package names (issue 83). The `golangci/golangci-lint`
image is Debian-based and has no `apk`, so the old `apk add` instruction
failed as written. Nothing is pinned or unpinned; that is still open on
issue 72.
- 2026-10-04: `REPO_POLICIES.md` now says which `Dockerfile` stages run
`script/bootstrap` (issue 90). The gate phases and the build stage take their
tools from their pinned base images and install only what those images lack,
as the canonical Go `Dockerfile` does. The development environment stage, the
final stage of a non-server repo, runs `script/bootstrap`. The new repo
checklist says the same.
- 2026-10-04: Fixed the server lifecycle example in
`prompts/GO_HTTP_SERVER_CONVENTIONS.md` (issue 86). Only fx handles SIGINT and
SIGTERM, and `Run()` in `main` exits with the shutdown's exit code. A listen
+4 -9
View File
@@ -63,15 +63,10 @@ with your task.
here run anywhere other than the repo root, the anchored entry misses
`services/api/.claude/`: add anchored entries for those directories.
- [ ] If the repo embeds a version in a binary: `.dockerignore` lets `.git` into
the build context. It keeps out every git `config` at any depth
(`**/.git/config`, `**/.git/modules/**/config`): the repository's own,
each submodule's under `.git/modules/`, and that of a submodule keeping
its own `.git` directory. `git describe` does not need them, and each can
hold a credential: a password in a remote URL, or the token the CI
checkout step stores there. A submodule whose name has a `config` segment
(`config`, `deploy/config`, `config/lib`) loses its whole git directory to
`**/.git/modules/**/config`, and Go's version stamping then fails the
build: give it a name without that segment (`git submodule add --name`).
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
+6 -11
View File
@@ -71,15 +71,10 @@ Template files can be fetched from:
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 every git `config` at any depth
(`**/.git/config`, `**/.git/modules/**/config`): the repository's own,
each submodule's under `.git/modules/`, and that of a submodule keeping
its own `.git` directory. `git describe` does not need them, and each can
hold a credential: a password in a remote URL, or the token the CI
checkout step stores there. A submodule whose name has a `config` segment
(`config`, `deploy/config`, `config/lib`) loses its whole git directory to
`**/.git/modules/**/config`, and Go's version stamping then fails the
build: give it a name without that segment (`git submodule add --name`).
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
@@ -124,8 +119,8 @@ are thin shims calling them. Model scripts:
- [ ] `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
archive; pinned yarn via corepack); a non-server repo's development
environment stage 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 .`,
+13 -26
View File
@@ -104,10 +104,12 @@ style conventions are in separate documents:
`lint` phase and a `test` phase, with the final stage depending on both so the
image cannot be built unless they pass. For non-server repos the final stage
brings up a development environment; for server repos it is the runtime image.
Dockerfiles install development prerequisites by running `script/bootstrap`
rather than duplicating installs inline; COPY `script/` and the dependency
manifests (`package.json` + `yarn.lock`, `go.mod` + `go.sum`, etc.) before
running it.
The gate phases and the build stage take their tools from their pinned base
images and install only what those images lack, as the canonical Go
`Dockerfile` below does. The development environment stage installs
development prerequisites by running `script/bootstrap` rather than
duplicating its installs inline; COPY `script/` and the dependency manifests
(`package.json` + `yarn.lock`, `go.mod` + `go.sum`, etc.) before running it.
- **Linting and testing run in Docker, as phases of the `Dockerfile`.** There is
no separate lint file. `script/lint` and `script/test` each build one phase
@@ -236,28 +238,13 @@ style conventions are in separate documents:
(e.g. a web frontend compiled in a separate stage), the lint phase must
create placeholder files so the embed directives resolve. Example:
`RUN mkdir -p web/dist && touch web/dist/index.html web/dist/style.css`.
- If the project requires CGO or system libraries for linting, install them
in the lint phase. The `golangci/golangci-lint` image is Debian-based and
has no `apk`, so install with `apt-get` under the Debian package name
(`libvips-dev`, where alpine says `vips-dev`), and delete the package
lists in the same `RUN`, so the layer does not keep them:
```dockerfile
RUN apt-get update \
&& apt-get install -y --no-install-recommends libvips-dev \
&& rm -rf /var/lib/apt/lists/*
```
- `.dockerignore` lets `.git` into the build context. It keeps out every git
`config` at any depth (`**/.git/config`, `**/.git/modules/**/config`): the
repository's own, each submodule's under `.git/modules/`, and that of a
submodule keeping its own `.git` directory. `git describe` does not need
them, and each can hold a credential: a password in a remote URL, or the
token the CI checkout step stores there. A submodule whose name has a
`config` segment (`config`, `deploy/config`, `config/lib`) loses its whole
git directory to `**/.git/modules/**/config`, and Go's version stamping
then fails the build: give it a name without that segment
(`git submodule add --name`). The stage that compiles has `git` (the
- If the project requires CGO or system libraries for linting (e.g.
`vips-dev`), install them in the lint phase with `apk add`.
- `.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