2 Commits
Author SHA1 Message Date
sneak 25ae960e63 Say where a repository's own .gitignore and .editorconfig entries go (closes #103)
check / check (push) Successful in 53s
The canonical `.gitignore` and `.editorconfig` now each end with a comment saying a repository's own entries go below it and a re-vendor keeps them, as `.dockerignore`'s header already does; without it a re-vendor dropped a repository's binaries and test outputs from `.gitignore`. `.editorconfig` gains `[*.go]` with tabs, since `gofmt` decides Go indentation in every repository. `prompts/REPO_POLICIES.md`, both checklists and the Go styleguide say the same in plain sentences. Common outputs such as `*.test` stay out of the canonical `.gitignore`. This also covers #104.

Model: opus-5-5
2026-10-06 01:33:35 +00:00
clawbot b09fff488b Assign the image tag on its own line in script/ (closes #101)
check / check (push) Successful in 49s
`script/cibuild`, `script/docker`, `script/lint` and `script/test` passed the image tag from `script/projectname` inline in the `docker build` arguments. A failing command substitution inside an argument does not trip `set -e`, so the scripts went on to `docker build` with an empty, `-lint` or `-test` tag, against the rule their own comment states. Each now assigns `tag` on its own line before `docker build`, so the script stops where `script/projectname` fails. The snippets in `prompts/REPO_POLICIES.md` show the same form, and the policy states the own-line rule.

Consuming repositories pick this up on their next re-vendor; the defect failed closed.

Model: opus-5-5
2026-10-06 02:52:23 +02:00
11 changed files with 99 additions and 40 deletions
+6
View File
@@ -10,3 +10,9 @@ insert_final_newline = true
[Makefile] [Makefile]
indent_style = tab indent_style = tab
[*.go]
indent_style = tab
# This repository's own sections, such as one for another language it
# uses, go below this comment, and a re-vendor keeps them.
+5 -1
View File
@@ -27,7 +27,7 @@ node_modules/
# Environment files. `*.env` covers bare `.env` and the `prod.env` # Environment files. `*.env` covers bare `.env` and the `prod.env`
# convention. Only the templates `example.env` and `sample.env` are # convention. Only the templates `example.env` and `sample.env` are
# re-included below. A repository that commits any other template adds # re-included below. A repository that commits any other template adds
# its own negation after these lines, for example `!.env.example`. # its own negation at the end of this file, for example `!.env.example`.
*.[eE][nN][vV] *.[eE][nN][vV]
.[eE][nN][vV].* .[eE][nN][vV].*
.[eE][nN][vV][rR][cC] .[eE][nN][vV][rR][cC]
@@ -45,3 +45,7 @@ node_modules/
[iI][dD]_[eE][cC][dD][sS][aA]_[sS][kK] [iI][dD]_[eE][cC][dD][sS][aA]_[sS][kK]
[iI][dD]_[eE][dD]25519 [iI][dD]_[eE][dD]25519
[iI][dD]_[eE][dD]25519_[sS][kK] [iI][dD]_[eE][dD]25519_[sS][kK]
# This repository's own entries, such as its build outputs, go below
# this comment, and a re-vendor keeps them. Anchor a binary built at the
# root: `/myapp`, never `myapp`, which also ignores `cmd/myapp/`.
+16
View File
@@ -21,6 +21,22 @@ fmt-check, and commit.
# Completed Steps # Completed Steps
- 2026-10-06: The canonical `.gitignore` and `.editorconfig` now each end with a
comment saying the repository's own entries go below it and a re-vendor keeps
them (issue 103, which took in issue 104), as `.dockerignore`'s header already
does. `.editorconfig` gains a `[*.go]` section with tabs, since `gofmt`
decides Go indentation everywhere. `REPO_POLICIES.md` and both checklists say
that each of these two files is the canonical content followed by the
repository's own entries, which a re-vendor keeps, and the Go styleguide puts
`*.log`, `*.out`, `*.test` and binaries among those entries. Common outputs
stay out of the canonical `.gitignore`; each repository lists its own.
- 2026-10-05: `script/cibuild`, `script/docker`, `script/lint` and `script/test`
now assign the image tag from `script/projectname` on its own line before the
`docker build` (issue 101), so `set -e` stops the script where
`script/projectname` fails instead of running `docker build` with a broken
tag. The comment above it in each script says why, and the snippets in
`REPO_POLICIES.md` show the same form. Repositories pick this up on their next
re-vendor.
- 2026-10-04: Went through the fleet findings recorded on 2026-08-09 (issue 62) - 2026-10-04: Went through the fleet findings recorded on 2026-08-09 (issue 62)
and added the two rules `REPO_POLICIES.md` did not yet state: a new or changed and added the two rules `REPO_POLICIES.md` did not yet state: a new or changed
check is proven by planting a defect it must catch; and a change to a separate check is proven by planting a defect it must catch; and a change to a separate
+4 -3
View File
@@ -1,6 +1,6 @@
--- ---
title: Code Styleguide — Go title: Code Styleguide — Go
last_modified: 2026-10-04 last_modified: 2026-10-06
--- ---
1. Try to hard wrap long lines at 77 characters or less. 1. Try to hard wrap long lines at 77 characters or less.
@@ -148,8 +148,9 @@ last_modified: 2026-10-04
handle HTTP requests. Don't use methods or your top level functions as handle HTTP requests. Don't use methods or your top level functions as
handlers. handlers.
1. Provide a .gitignore file that ignores at least `*.log`, `*.out`, and 1. The repository's own entries at the end of `.gitignore`, which a re-vendor
`*.test` files, as well as any binaries. keeps, ignore at least `*.log`, `*.out`, and `*.test` files, as well as any
binaries.
1. Constructors **must** be called `New()`. `modulename.New()` works great if 1. Constructors **must** be called `New()`. `modulename.New()` works great if
you name the packages properly. If the constructor creates an instance from you name the packages properly. If the constructor creates an instance from
+10 -5
View File
@@ -1,6 +1,6 @@
--- ---
title: Existing Repo Checklist title: Existing Repo Checklist
last_modified: 2026-10-04 last_modified: 2026-10-06
--- ---
Use this checklist when beginning work in a repo that may not yet conform to our Use this checklist when beginning work in a repo that may not yet conform to our
@@ -28,13 +28,18 @@ with your task.
root — never a file or directory named after one agent tool, such as root — never a file or directory named after one agent tool, such as
`CLAUDE.md` or `.claude/`, and never separate memory files. Move what any `CLAUDE.md` or `.claude/`, and never separate memory files. Move what any
such committed file says into `AGENTS.md` and delete it. such committed file says into `AGENTS.md` and delete it.
- [ ] `.gitignore` is comprehensive (OS, editor, agent scratch, language - [ ] `.gitignore` is comprehensive (OS, editor, agent scratch, secrets, the
artifacts, secrets) — fetch from repo's own build outputs) — fetch from
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore` if missing. `https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore` if missing.
An existing repo usually has a hand-written one that is never re-fetched, An existing repo usually has a hand-written one that is never re-fetched,
so check the entries rather than the file's presence. so check the entries rather than the file's presence. The file is the
canonical content followed by the repo's own entries, such as its
binaries; a re-vendor replaces the canonical part and keeps those entries.
- [ ] `.editorconfig` exists — fetch from - [ ] `.editorconfig` exists — fetch from
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig` `https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig`. The
file is the canonical content followed by the repo's own sections, such as
one for another language it uses; a re-vendor replaces the canonical part
and keeps those sections.
- [ ] `Dockerfile` and `.dockerignore` exist; the Dockerfile carries a `lint` - [ ] `Dockerfile` and `.dockerignore` exist; the Dockerfile carries a `lint`
phase and a `test` phase, and the final stage carries a `COPY --from=` of phase and a `test` phase, and the final stage carries a `COPY --from=` of
a harmless file from each — fetch `.dockerignore` from a harmless file from each — fetch `.dockerignore` from
+11 -8
View File
@@ -1,6 +1,6 @@
--- ---
title: New Repo Checklist title: New Repo Checklist
last_modified: 2026-10-04 last_modified: 2026-10-06
--- ---
Use this checklist when creating a new repository from scratch. Follow the steps Use this checklist when creating a new repository from scratch. Follow the steps
@@ -34,14 +34,17 @@ Template files can be fetched from:
## Fetch Template Files ## Fetch Template Files
- [ ] `.gitignore` — fetch from - [ ] `.gitignore` — fetch from
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore`, extend for `https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore`, then add
language-specific artifacts. Extensions are written to `.gitignore`'s own the repo's own build outputs, such as its binaries, at the end of the
semantics, where an unanchored pattern already matches at every depth: file, where a re-vendor keeps them. Extensions are written to
never add a `**/` prefix here, which is a `.dockerignore` form. The `.gitignore`'s own semantics, where an unanchored pattern already matches
canonical file already carries `.claude/` so agent worktrees cannot be at every depth: never add a `**/` prefix here, which is a `.dockerignore`
committed by accident. form. The canonical file already carries `.claude/` so agent worktrees
cannot be committed by accident.
- [ ] `.editorconfig` — fetch from - [ ] `.editorconfig` — fetch from
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig` `https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig`, then
add the repo's own sections, such as one for another language it uses, at
the end of the file, where a re-vendor keeps them.
- [ ] `Makefile` — fetch from - [ ] `Makefile` — fetch from
`https://git.eeqj.de/sneak/prompts/raw/branch/main/Makefile`, adapt `https://git.eeqj.de/sneak/prompts/raw/branch/main/Makefile`, adapt
targets for the project's language and tools targets for the project's language and tools
+23 -11
View File
@@ -1,6 +1,6 @@
--- ---
title: Repository Policies title: Repository Policies
last_modified: 2026-10-04 last_modified: 2026-10-06
--- ---
This document covers repository structure, tooling, and workflow standards. Code This document covers repository structure, tooling, and workflow standards. Code
@@ -118,8 +118,9 @@ style conventions are in separate documents:
and nothing else: and nothing else:
```sh ```sh
docker build --no-cache --target lint -t "$(script/projectname)-lint" . tag="$(script/projectname)"
docker build --no-cache --target test -t "$(script/projectname)-test" . docker build --no-cache --target lint -t "$tag-lint" .
docker build --no-cache --target test -t "$tag-test" .
``` ```
**A stage that is not the last one in the file is built only when the final **A stage that is not the last one in the file is built only when the final
@@ -132,7 +133,9 @@ style conventions are in separate documents:
**Every `docker build` in `script/` is tagged**, here and in **Every `docker build` in `script/` is tagged**, here and in
`script/cibuild` and `script/docker`. An untagged build leaves a dangling `script/cibuild` and `script/docker`. An untagged build leaves a dangling
image behind on every invocation, on every developer host and every CI image behind on every invocation, on every developer host and every CI
runner; a tagged one replaces the previous image. runner; a tagged one replaces the previous image. Each script assigns the
tag on its own line before the build, so `set -e` stops it where
`script/projectname` fails.
Inside a phase the tool is invoked directly — `golangci-lint`, `go test`, Inside a phase the tool is invoked directly — `golangci-lint`, `go test`,
`eslint`, `prettier` — never through `make lint` or `script/test`, which are `eslint`, `prettier` — never through `make lint` or `script/test`, which are
@@ -384,9 +387,12 @@ style conventions are in separate documents:
- `.gitignore` should be comprehensive from the start: OS files (`.DS_Store`), - `.gitignore` should be comprehensive from the start: OS files (`.DS_Store`),
editor files (`.swp`, `*~`), in-repo agent scratch directories (`.claude/`), editor files (`.swp`, `*~`), in-repo agent scratch directories (`.claude/`),
language build artifacts, and `node_modules/`. Fetch the standard `.gitignore` `node_modules/`, and the repo's own build outputs. Fetch the standard
from `https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore` when `.gitignore` from
setting up a new repo. These patterns are written to `.gitignore`'s own `https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore` when setting up
a new repo. A repo's `.gitignore` is the standard file followed by the repo's
own entries, such as its binaries; a re-vendor replaces the standard part and
keeps those entries. These patterns are written to `.gitignore`'s own
semantics, in which an unanchored pattern already matches at every depth; they semantics, in which an unanchored pattern already matches at every depth; they
are not a `.dockerignore` and must not be transplanted into one unmodified. are not a `.dockerignore` and must not be transplanted into one unmodified.
@@ -434,13 +440,15 @@ style conventions are in separate documents:
byte-identically across repos: byte-identically across repos:
```sh ```sh
# Own line: a failing command substitution inside an argument does not # The version and the tag each get their own line: a failing command
# trip `set -e`, so the inline form degrades to an empty constant. # substitution inside an argument does not trip `set -e`, so the inline
# form degrades to an empty constant.
version="$(git describe --tags --always --dirty 2>/dev/null || true)" version="$(git describe --tags --always --dirty 2>/dev/null || true)"
[ -n "$version" ] || version="unknown" [ -n "$version" ] || version="unknown"
tag="$(script/projectname)"
docker build --no-cache \ docker build --no-cache \
--build-arg VERSION="$version" \ --build-arg VERSION="$version" \
-t "$(script/projectname)" . -t "$tag" .
``` ```
`--always` makes an untagged repo yield an abbreviated commit hash rather `--always` makes an untagged repo yield an abbreviated commit hash rather
@@ -636,7 +644,11 @@ style conventions are in separate documents:
Never edit existing migrations after release. Never edit existing migrations after release.
- All repos should have an `.editorconfig` enforcing the project's indentation - All repos should have an `.editorconfig` enforcing the project's indentation
settings. settings: the standard file from
`https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig`, which sets
tabs for `Makefile` and Go files, followed by the repo's own sections, such as
one for another language it uses. A re-vendor replaces the standard part and
keeps those sections.
- Avoid putting files in the repo root unless necessary. Root should contain - Avoid putting files in the repo root unless necessary. Root should contain
only project-level config files (`README.md`, `AGENTS.md`, `Makefile`, only project-level config files (`README.md`, `AGENTS.md`, `Makefile`,
+7 -5
View File
@@ -14,15 +14,17 @@ main() {
cd "$ROOT" cd "$ROOT"
"$SCRIPT_DIR/bootstrap" "$SCRIPT_DIR/bootstrap"
"$SCRIPT_DIR/check" "$SCRIPT_DIR/check"
# Own line: a failing command substitution inside an argument does # The version and the tag each get their own line: a failing
# not trip `set -e`, so the inline form degrades silently to an # command substitution inside an argument does not trip `set -e`,
# empty constant. The VERSION build argument takes precedence over # so the inline form degrades silently to an empty constant. The
# the version a build stage derives from the .git in the context. # VERSION build argument takes precedence over the version a build
# stage derives from the .git in the context.
version="$(git describe --tags --always --dirty 2>/dev/null || true)" version="$(git describe --tags --always --dirty 2>/dev/null || true)"
[ -n "$version" ] || version="unknown" [ -n "$version" ] || version="unknown"
tag="$("$SCRIPT_DIR/projectname")"
docker build --no-cache \ docker build --no-cache \
--build-arg VERSION="$version" \ --build-arg VERSION="$version" \
-t "$("$SCRIPT_DIR/projectname")" . -t "$tag" .
} }
main "$@" main "$@"
+7 -5
View File
@@ -10,15 +10,17 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() { main() {
cd "$ROOT" cd "$ROOT"
# Own line: a failing command substitution inside an argument does # The version and the tag each get their own line: a failing
# not trip `set -e`, so the inline form degrades silently to an # command substitution inside an argument does not trip `set -e`,
# empty constant. The VERSION build argument takes precedence over # so the inline form degrades silently to an empty constant. The
# the version a build stage derives from the .git in the context. # VERSION build argument takes precedence over the version a build
# stage derives from the .git in the context.
version="$(git describe --tags --always --dirty 2>/dev/null || true)" version="$(git describe --tags --always --dirty 2>/dev/null || true)"
[ -n "$version" ] || version="unknown" [ -n "$version" ] || version="unknown"
tag="$("$SCRIPT_DIR/projectname")"
docker build --no-cache \ docker build --no-cache \
--build-arg VERSION="$version" \ --build-arg VERSION="$version" \
-t "$("$SCRIPT_DIR/projectname")" . -t "$tag" .
} }
main "$@" main "$@"
+5 -1
View File
@@ -15,9 +15,13 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() { main() {
cd "$ROOT" cd "$ROOT"
# The tag gets its own line: a failing command substitution inside
# an argument does not trip `set -e`, so the inline form degrades
# silently to an empty constant.
tag="$("$SCRIPT_DIR/projectname")"
docker build --no-cache \ docker build --no-cache \
--target lint \ --target lint \
-t "$("$SCRIPT_DIR/projectname")-lint" . -t "$tag-lint" .
} }
main "$@" main "$@"
+5 -1
View File
@@ -11,9 +11,13 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() { main() {
cd "$ROOT" cd "$ROOT"
# The tag gets its own line: a failing command substitution inside
# an argument does not trip `set -e`, so the inline form degrades
# silently to an empty constant.
tag="$("$SCRIPT_DIR/projectname")"
docker build --no-cache \ docker build --no-cache \
--target test \ --target test \
-t "$("$SCRIPT_DIR/projectname")-test" . -t "$tag-test" .
} }
main "$@" main "$@"