]> git.giacomolli.uk - onechat/blob - .agents/skills/go-code/SKILL.md
a9e705b7d1c53ecae9d952b35def3a5d4859dcf2
[onechat] / .agents / skills / go-code / SKILL.md
1 ---
2 name: go-code
3 description: Go style rules. Use before you write or review Go code.
4 ---
5
6 # Go code
7
8 ## Packages and files
9
10 - Keep Go code in one root `main` package. Do not add `internal/`,
11 `cmd/`, or one-file packages until the user asks for them.
12 - Keep `main.go` limited to the entry point. Name other files for their
13 function. Do not create `main_test.go`.
14 - A file carries its own context. Keep each struct and all of its
15 methods in one file. Give a separate responsibility its own type.
16 - When code in one file gets a user in another file for an unrelated
17 purpose, move it to a file named for its function in the same change.
18 - Put entry points first, then each struct's methods as a group, then
19 standalone utility functions. Do not put a utility function between
20 the methods of one type.
21 - In each group, order functions by first use in the file.
22
23 ## Entry point and context
24
25 - `main` calls `run()` and handles its returned error. Do not use
26 `log.Fatal`.
27 - `run()` creates the SIGINT/SIGTERM signal context and defers its
28 cancellation. Pass that context through operations and let cleanup
29 finish before `main` exits.
30 - Use `ctx` for a context and `cancel` for its cancellation function.
31 Call `defer cancel()` immediately after you create the context.
32 - Reuse `ctx` when a child context replaces its parent. Use a different
33 name only when both contexts stay in use. Return `ctx.Err()` directly.
34
35 ## Errors
36
37 - Handle every returned error.
38 - Reuse an existing `err` for later operations in the same scope. Use a
39 different variable only to keep or join errors.
40 - Use `errors.Is` and `errors.As` to examine errors. Do not compare an
41 error directly with a sentinel, because errors can be wrapped.
42 - When a function has more than one error path, wrap each returned error
43 with the context of its operation. A function with one error path can
44 return the error directly.
45 - When deferred cleanup can fail, use a named `err` result and join the
46 cleanup error with `errors.Join`.
47
48 ## Style
49
50 - Keep function signatures on one line. Write function bodies on more
51 than one line, also for anonymous functions, deferred cleanup, and
52 test callbacks.
53 - Do not use short `if` initializers.
54 - Use a one-letter receiver name for each method.
55 - Use field names in struct literals. Put each field on its own line
56 when you set more than one field. This includes the cases of a
57 table-driven test. A small type of two fields that acts as one value,
58 such as a key or a coordinate pair, can use a positional literal on
59 one line.
60 - Put an empty line between logical blocks, also after multiline
61 declarations, assignments, literals, and calls. Keep an operation with
62 its immediate error or result check. Keep a short declaration with its
63 immediate use.
64 - Use GNU-style command flags: two dashes for long flags, such as
65 `--cwd`, and one dash only for one-letter flags, such as `-h`.
66 - Prefer the Go standard library. Prefer Go over cgo.
67 - Do not add compile-time interface assertions. Prove compatibility
68 through actual assignments and calls.
69 - Use `// nolint: name` for lint directives.
70
71 ## Dependencies
72
73 - After a change to `go.mod` or `go.sum`, update `vendorHash` in
74 `nix/package.nix`. While the module has no dependencies, `vendorHash`
75 is `null`.
76
77 ## Tests
78
79 - Add tests for meaningful behavior. Do not add tests that only repeat
80 implementation details.
81 - Use `testify/require` for assertions.
82 - Name a table-driven case slice `testCases` and its range variable
83 `tc`. A subtest name describes the behavior, not a generic outcome or
84 input.
85 - In a test file, put constants immediately after the imports, then the
86 tests, then supporting types, methods, and helpers.
87 - Supply valid required dependencies in tests. Do not make a dependency
88 optional only to make a test simpler.