1. Format all files with `bin/format`.
2. Run the checks with `bin/check`. Its golangci-lint config keeps the
standard linters and adds `errorlint`, `gocritic`, `testifylint`,
- `revive`, `wrapcheck`, `nlreturn`, and `wsl_v5`. The settings in
- `.golangci.yml` match the Go rules.
+ `revive`, `wrapcheck`, `nlreturn`, and `wsl_v5`. These checks cover
+ only part of the Go rules. A pass is not proof of compliance.
3. Run `git add` on new files, then run `nix build` and
`nix flake check`.
4. Fix every failure and run the steps again. Do not disable a linter or
- add a `nolint` directive to get a pass, unless the user agrees.
+ add a `nolint` directive to get a pass. An intentional error discard
+ needs the user's approval, an explicit directive, and a comment that
+ gives the reason, as the `go-code` skill requires. Never replace a
+ checked error with a blank assignment to get a pass.
5. Review the final diff against the rules. Passing tools do not replace
this review.
- Read `AGENTS.md` and the `SKILL.md` of each skill of the task again
from disk now. Do not work from memory of an earlier read.
- Go through the diff one rule at a time, and for each rule look at
every changed line that it covers. For Go code, check each section
- of `go-code`, also for the tests.
+ of `go-code`, also for the tests. Check declaration order, owning
+ test filenames, separators after multiline constructs, and errors
+ assigned to `_`. Inspect blank-assigned errors even when `errcheck`
+ reports none: `.golangci.yml` does not enable its `check-blank`
+ setting. Check whole comment paragraphs against the `docs` skill,
+ not only their line width.
- Fix each finding, then run steps 1 to 4 again.
Tell the user about each check that cannot run and each failure that
## Procedure
-1. Do the `check` skill. All checks must pass before you commit.
-2. Stage only the files that belong to this change. Keep unrelated
+1. Confirm that the configured signing key is available. If signing is
+ unavailable or fails, stop and report the problem. Never disable
+ signing, bypass it with a command or configuration override, or
+ create an unsigned commit.
+2. Do the `check` skill. All checks must pass before you commit.
+3. Stage only the files that belong to this change. Keep unrelated
changes in separate commits.
-3. Write the message to a file or a here-document and commit with
- `git commit -F`. Never put `\n` in `git commit -m`.
-4. When `.githooks/commit-msg` rejects the message, fix the message and
+4. Write the message to a file or a here-document and sign the commit
+ with the configured key, using `git commit -S -F`. Never put `\n` in
+ `git commit -m`.
+5. When `.githooks/commit-msg` rejects the message, fix the message and
commit again. Do not skip the hook with `--no-verify`.
+6. Cryptographically verify each new commit's signature against the
+ configured key before reporting completion. A signature header alone
+ is not verification. If verification fails, stop and report it. Do
+ not claim completion or publish the commit.
## Size
- Commit often. Split the work into small, coherent, working steps, and
do not wait for a full feature.
-- Before a push, rebase on the latest `master` and fix conflicts during
- the rebase. Never make a merge commit.
+- Push code only with the user's authorization. A remote does not give
+ permission to push.
+- Rebase before an authorized push only when the task permits it. Do not
+ rewrite published commits without the user's explicit approval. Stop
+ and ask when an operation needs that approval. Never make a merge
+ commit.
## Subject
## Trailers
- When the change belongs to an issue, end the message with one `Issue:`
- trailer with the git-bug ID of that issue. Add it with
- `git commit --trailer`. Never use a closing keyword such as "Fixes" or
- "Closes".
+ trailer. Use the shortest unique git-bug issue ID in the `Issue:`
+ trailer, with a minimum of seven characters. Check uniqueness against
+ all issues, not only open issues. Add it with `git commit --trailer`.
+ Never use a closing keyword such as "Fixes" or "Closes".
- Link the bug report when a change fixes a reported bug.
- Do not add an AI tool as co-author. Do not add attribution trailers.
case.
- Write all the letters of an initialism in one case. `revive` checks
common initialisms.
-- Put entry points first, then each struct's methods as a group, then
- standalone utility functions. Do not put a utility function between
- the methods of one type.
-- In each group, order functions by first use in the file.
+- Order declarations as imports, constants, variables, types,
+ constructors, methods, then standalone helpers. Types include structs,
+ interfaces, and aliases. Put all types before any constructor or
+ method, also when a file holds more than one type. The Tests section
+ gives the exception for files with tests.
+- Keep each type's methods in one group. Do not put a helper between
+ them. Order functions by first use within their declaration group, not
+ across groups. Entry points do not go before types or constructors
+ merely because they are entry points.
## Entry point and context
## Errors
-- Handle every returned error.
+- Handle every returned error, including an error assigned to `_`. Never
+ use a blank assignment to hide an unchecked error from a linter.
+ Handle meaningful errors. When the user approves an intentional
+ discard, call the operation with an explicit `// nolint: errcheck`
+ directive and a comment that gives the reason, not a blank assignment.
+ The `check` skill gives the approval rule.
- Reuse an existing `err` for later operations in the same scope. Use a
different variable only to keep or join errors.
- Use `errors.Is` and `errors.As` to examine errors. Do not compare an
table-driven test. A small type of two fields that acts as one value,
such as a key or a coordinate pair, can use a positional literal on
one line.
-- Put an empty line between logical blocks, also after multiline
- declarations, assignments, literals, and calls. Keep an operation with
- its immediate error or result check. Keep a short declaration with its
- immediate use. `wsl_v5` and `nlreturn` check part of this rule. Review
- the remaining logical blocks and immediate-use groups by hand.
+- Put an empty line between logical blocks and after multiline
+ declarations, assignments, literals, and calls. The only exception
+ after a multiline construct is its immediate error check. Separate a
+ multiline literal from a following loop, even when the loop uses that
+ literal. Keep a single-line declaration with its immediate use, and an
+ operation with its immediate error check. This does not waive the
+ separator after a multiline construct. `wsl_v5` and `nlreturn` check
+ only part of this rule. Review the other boundaries by hand.
- Use GNU-style command flags: two dashes for long flags, such as
`--cwd`, and one dash only for one-letter flags, such as `-h`.
- Prefer the Go standard library. Prefer Go over cgo.
- Name a table-driven case slice `testCases` and its range variable
`tc`. A subtest name describes the behavior, not a generic outcome or
input.
-- In a test file, put constants immediately after the imports, then the
- tests, then supporting types, methods, and helpers.
+- Each file with tests must have the name of its owning production file
+ with `_test` before `.go`: `memory_test.go` tests `memory.go`. Move
+ scenario and integration tests into their owner's test file. Do not
+ add an empty production file to make a test filename valid. Only
+ `_helper_test.go` files are exempt from this pairing rule.
+- In an ordinary `_test.go` file, order declarations as imports,
+ constants, variables, tests, supporting types, constructors, methods,
+ then helpers. This tests-first order is the exception to the
+ production order. Put all supporting types before their constructors
+ and methods.
+- A `_helper_test.go` file has no tests. Order its declarations as
+ imports, constants, variables, types, constructors, methods, then
+ helpers, as in a production file.
- Keep a helper that only one test file uses in that file. Put a helper
that more than one test file uses in a file without tests. Name that
file for what it holds, and end the name with `_helper_test.go`.
qualifier. Nothing checks the trailers. Before you close a parent, make
sure that its children are closed.
-Push the issues with `git bug push` when the repository has a remote.
+Push issues with `git bug push` only when the user authorizes it. A
+remote does not give permission to push. Do not rewrite published
+history without the user's explicit approval.
This example creates an issue: