Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/links.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: links

# Every URL a skill, agent, rule, or doc cites must still resolve — a moved page is a hole in a
# rule's provenance. Needs the network, so it runs apart from `validate`: weekly, on demand, and on
# pull requests that touch the files that carry citations or the checker/workflow that resolves them.
on:
schedule:
- cron: '0 6 * * 1'
workflow_dispatch:
pull_request:
paths:
- 'skills/**'
- 'agents/**'
- 'rules/**'
- 'docs/**'
- 'README.md'
- 'AGENTS.md'
- 'scripts/validate.py'
- '.github/workflows/links.yml'

jobs:
links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- run: python3 scripts/validate.py --check-links
5 changes: 3 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ This plugin encodes **Go (golang) coding standards**. Guidance must be grounded
- **Style references** (cite these when a rule depends on them):
- **Effective Go** — <https://go.dev/doc/effective_go>
- **Go Code Review Comments** — <https://go.dev/wiki/CodeReviewComments>
- **Google Go Style Guide** — <https://google.github.io/styleguide/go/>
- **Google Go Style Guide** — <https://google.github.io/styleguide/go/> — cite the document a rule comes from: the *Guide* (normative and canonical; the ordered principles), *Style Decisions* (normative; the reviewer rulebook), *Best Practices* (advisory)
- **Uber Go Style Guide** — <https://github.com/uber-go/guide>
- **Linter rule catalogues** — name the rule when a skill says a tool catches something: `go vet` <https://pkg.go.dev/cmd/vet>, staticcheck <https://staticcheck.dev/docs/checks/>, revive <https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md>
- **Standard library & toolchain** — package docs at <https://pkg.go.dev>; modules, `go test`, table-driven tests, and the race detector (`go test -race`) are the baseline testing conventions.

When a recommendation derives from one of the above, attribute it explicitly and distinguish cited rules from inference.
Expand All @@ -39,7 +40,7 @@ This repo supports **both Claude Code and Cursor**. Shared assets (skills, comma
- **Cursor hooks**: `hooks/cursor-hooks.json` — object `{ "hooks": { "sessionStart": [...], "afterFileEdit": [...] } }`; the command runs from the plugin root (a **workspace-relative** path, **not** `${CLAUDE_PLUGIN_ROOT}`). Present — wires `session-start.sh` (`sessionStart`) and `format-on-save.sh` + `skill-nudge.sh` (`afterFileEdit`).
- **Shared hook scripts**: `hooks/session-start.sh` — detects `go.mod` / `*.go`, prints one Go-standards context line, exits 0 always. `hooks/format-on-save.sh` — after a `*.go` Write/Edit, runs `gofumpt -w` (or `gofmt -w -s`) on that single file; resolves the path from `$CLAUDE_FILE_PATH` or the stdin tool-payload JSON, host-only, silent no-op if no formatter is installed, exits 0 always. `hooks/skill-nudge.sh` — after a `*.go` Write/Edit, names ONE matching go-coding skill for that edit, once per skill per session; delivered as a hook `systemMessage` under Claude Code, a plain line under Cursor; exits 0 always. All three host-agnostic so either manifest can invoke them. Present.
- **MCP config** *(optional, not present)*: `.mcp.json` — only if the plugin later integrates an MCP server. There is no companion MCP server today; do not reference one.
- **Validation**: `scripts/validate.sh` wraps `scripts/validate.py` to check both manifests, dual-host parity, declared component paths, kebab-case names, hook-config JSON, skill/command/agent frontmatter (**agents must use `tools:` not `allowed-tools:`** — flagged as an error), hook parity (the same `hooks/*.sh` wired for the equivalent event on both hosts, each one existing and executable, none left unwired), doc component inventories (every shipped skill, agent and hook named in `README.md`, this file, and `docs/testing.md`; hooks alone in `docs/install.md`), and two *advice == tooling* invariants: every linter taught in a component is enabled in `references/golangci.v2.yml`, and (when a floor-minor Go toolchain is on PATH — CI's matrix installs `1.26.x` and `1.27.x`; the strict check runs on the 1.26.x (floor) leg, the 1.27.x leg soft-skips it) the `go-idioms` Fixer column matches `go tool fix help`. The Python is stdlib-only. `.github/workflows/validate.yml` pins Python + Go and runs the validator strictly.
- **Validation**: `scripts/validate.sh` wraps `scripts/validate.py` to check both manifests, dual-host parity, declared component paths, kebab-case names, hook-config JSON, skill/command/agent frontmatter (**agents must use `tools:` not `allowed-tools:`** — flagged as an error), hook parity (the same `hooks/*.sh` wired for the equivalent event on both hosts, each one existing and executable, none left unwired), doc component inventories (every shipped skill, agent and hook named in `README.md`, this file, and `docs/testing.md`; hooks alone in `docs/install.md`), tie-break parity (the Google readability tie-break sentence reads identically in the `go-coding` router, `rules/go-context.mdc`, and `go-reviewer`), and two *advice == tooling* invariants: every linter taught in a component is enabled in `references/golangci.v2.yml` (analyzers a skill teaches as opt-in — `shadow` in `go-idioms` — are the deliberate exception: each is taught with the config line that switches it on, and is not added to the reference config at a refresh), and (when a floor-minor Go toolchain is on PATH — CI's matrix installs `1.26.x` and `1.27.x`; the strict check runs on the 1.26.x (floor) leg, the 1.27.x leg soft-skips it) the `go-idioms` Fixer column matches `go tool fix help`. The Python is stdlib-only. `.github/workflows/validate.yml` pins Python + Go and runs the validator strictly.
- **Contributor docs**: `docs/` for human-facing references — `install.md`, `testing.md`, `versioning.md`, `authoring.md`. `.github/` holds issue + PR templates, `copilot-instructions.md`, and the CI workflow. (Planning and research working notes are kept locally under `docs/`, **gitignored** — not part of the published plugin.)

### Component surface
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Keep a Changelog: https://keepachangelog.com/en/1.1.0/
- Semantic Versioning: https://semver.org/spec/v2.0.0.html

## [Unreleased]

### Added
- Skills: `go-layout` — imports in groups with the standard library first, blank imports only in `main` or a test (the `embed` package under `//go:embed` excepted; a justifying comment is revive's alternate in a library), no dot imports (`revive` `blank-imports`/`dot-imports`), and field names in struct literals of types from other packages (`go vet` `composites`).
- Skills: `go-errors` — `MustX` helpers are for package initialisation from constant inputs or a test helper that `t.Fatal`s, never for input that can fail.
- Skills: `go-testing` — `Example` functions with `// Output:` as runnable documentation, advised where feasible rather than one per export (`go vet` `tests`), field names in table-case literals, and comparing stable results rather than serialised bytes or map order.
- Skills: `go-idioms` — a nested `:=` that shadows `err` or `ctx` (the `shadow` analyzer, opt-in), and the redundant `break` at the end of a `switch` case (staticcheck S1023).
- Skills: `go-coding`, `rules/go-context.mdc` — the tie-break order for two valid forms: clarity, simplicity (with least mechanism), concision, maintainability, consistency (Google Go Style Guide).
- Agents: `go-reviewer` — import and literal hygiene and test-fragility dimensions, a shadowed `err` and a `Must` helper on a request path under error swallowing, and the same tie-break order for style findings.
- Scripts: `validate.py --check-links` verifies every cited URL resolves (HEAD, then GET; one retry on a transport error or a 429/503), and `--selftest` exercises that policy against a local server with no network; `.github/workflows/links.yml` runs the live check weekly and on pull requests touching skills, agents, rules, docs, the checker, or the workflow.
- Scripts: `validate.py` checks that the tie-break sentence is identical in the `go-coding` router, the Cursor rule, and `go-reviewer`.

### Changed
- References: the source registry names Google's three documents by weight (Guide, Style Decisions, Best Practices), adds the linter rule catalogues to Tier 3, and records the revision read for each mutable source.
- Docs: `AGENTS.md` and `README.md` follow the registry.

## [0.5.0] - 2026-09-04

Makes the `go-coding` router route. A usage analysis of local session transcripts found the router
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Or load a local working copy for a single session: `claude --plugin-dir /path/to
| Cursor rule `go-context.mdc` | shipped | `**/*.go`-scoped guidance mirroring the router for Cursor. |
| Scripts `scripts/hooks-test.sh`, `scripts/usage-report.py` | shipped | Dev tooling, not part of the installed component surface: a bash test harness for the hooks, and a stdlib-only adoption-report generator over local session transcripts. |

Guidance is grounded in authoritative sources — [Effective Go](https://go.dev/doc/effective_go), [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments), the [Google](https://google.github.io/styleguide/go/) and [Uber](https://github.com/uber-go/guide) style guides — and the standard toolchain (`gofmt`/`gofumpt`, `go vet`, `staticcheck`, `golangci-lint`, `go test -race`).
Guidance is grounded in authoritative sources — [Effective Go](https://go.dev/doc/effective_go), [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments), the [Google Go Style Guide](https://google.github.io/styleguide/go/) (its *Guide*, *Style Decisions*, and *Best Practices*) and the [Uber Go Style Guide](https://github.com/uber-go/guide) — and the standard toolchain (`gofmt`/`gofumpt`, `go vet`, `staticcheck`, `golangci-lint`, `go test -race`).

## Using with subagent orchestrators

Expand Down
18 changes: 17 additions & 1 deletion agents/go-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ the judgment a linter cannot — the bugs and smells that survive `gofmt`, `go v

- **Silent error swallowing** — `_ = f()` on an error that matters; empty `if err != nil {}`; `%v`
where `%w` was needed (breaks downstream `errors.Is`/`errors.As`); returning `nil` after logging a
real failure.
real failure; a nested `:=` that shadows `err` so the outer check sees nil (`go-idioms`);
a `MustX` helper — panic on failure — called on a request path or on input the program does not
control (`go-errors`).
- **Goroutine leaks / lifetime** — a goroutine with no exit path; a channel send/recv after the
counterparty has returned; workers not tied to a `context` or done signal; `wg.Add`/`Done`
mismatch (prefer `wg.Go`).
Expand Down Expand Up @@ -115,11 +117,25 @@ the judgment a linter cannot — the bugs and smells that survive `gofmt`, `go v
`go fix ./...` or `golangci-lint run --enable-only=modernize`.
- **slog hot-path waste** — building a per-call logger instead of `logger.With(...)`; formatting or
allocating before a level check; key-value variadic on a hot path instead of `slog.LogAttrs`.
- **Import and literal hygiene** — `import .`; `import _` in a library package with neither a
`//go:embed` use of `embed` nor a comment justifying the side effect; a positional struct literal
of a type from another package. `revive` (`blank-imports`, `dot-imports`) and `go vet`
(`composites`) catch all three — name the rule (`go-layout`).
- **Test fragility** — a test comparing serialised bytes or formatted text from a package the repo
does not own, or map-derived output without sorting; `t.Fatal` called from a goroutine the test
started; a table whose long positional case literals have to be decoded against the struct
(`go-testing`).

For the *why* and citations behind any dimension, the `go-errors`, `go-concurrency`, `go-testing`,
`go-idioms`, `go-lint-setup`, and `go-layout` skills carry the grounded rules — reference them rather
than re-deriving from memory.

When a finding is about which of two valid forms to prefer and the tools accept both, rank by the
order Google's Go Style Guide gives — clarity, then simplicity (with its rule of least mechanism:
the most standard tool that expresses the idea), then concision, then maintainability, then
consistency — and say which attribute decided it (<https://google.github.io/styleguide/go/guide>). A
style preference with no attribute behind it is not a finding.

## Output format

Lead with a one-line verdict, then findings highest-severity first:
Expand Down
51 changes: 42 additions & 9 deletions docs/authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,21 @@ citation. Everything the skills assert should be traceable to one of these.
| Go Code Review Comments | <https://go.dev/wiki/CodeReviewComments> | the review-rule catalogue (naming, errors, concurrency, API shape) |
| Doc comment syntax | <https://go.dev/doc/comment> | `gofmt`-formatted doc comments, doc links |

**Tier 2 — style guides (attribute when a rule comes from one)**

- Google Go Style Guide — <https://google.github.io/styleguide/go/> (esp. `/best-practices`: naming,
error handling, panics, option structs, documentation, test structure)
**Tier 2 — style guides (attribute when a rule comes from one, and name the document)**

- Google Go Style Guide — three documents of different weight, ranked by Google itself; a citation
names which one:
- the *Guide* — <https://google.github.io/styleguide/go/guide> — **normative and canonical**: the five ordered readability principles
(clarity, simplicity, concision, maintainability, consistency) and, under simplicity, *least mechanism*. The
tie-break order the router, the Cursor rule and the reviewer use — one identical sentence in all
three, checked by `scripts/validate.py`.
- *Style Decisions* — <https://google.github.io/styleguide/go/decisions> — **normative, not canonical**: the reviewer rulebook — naming,
commentary, imports, errors, language, common libraries, useful test failures. The main Google
source for skill rules.
- *Best Practices* — <https://google.github.io/styleguide/go/best-practices> — **advisory**: patterns with trade-offs (test doubles, option structs,
error structure, shadowing, table-test literals).
Google-internal guidance is not adopted: flag conventions, Google's own logging library and
verbosity levels, protocol-buffer stubs, and CLI library choices.
- Uber Go Style Guide — <https://github.com/uber-go/guide>

**Tier 3 — the enforcing tools (this is what keeps "advice == tooling" true)**
Expand All @@ -81,7 +92,24 @@ citation. Everything the skills assert should be traceable to one of these.
- golangci-lint docs — <https://golangci-lint.run/docs/> · v1→v2 migration —
<https://golangci-lint.run/docs/product/migration-guide/> · changelog (for the CI pin) —
<https://golangci-lint.run/docs/product/changelog/>
- `go.dev/blog` for feature-specific posts (`synctest`, `testing-b-loop`, `slog`, `range-functions`)
- `go.dev/blog` for feature-specific posts (`synctest`, `testing-b-loop`, `slog`, `range-functions`,
`examples`)
- **Linter rule catalogues** — when a skill says a tool catches something, the rule id or name comes
from here, not from memory: `go vet` analyzers <https://pkg.go.dev/cmd/vet>; staticcheck checks
<https://staticcheck.dev/docs/checks/>; revive rules <https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md>; errorlint
<https://github.com/polyfloyd/go-errorlint>; gofumpt rules <https://github.com/mvdan/gofumpt#added-rules>;
the golangci-lint linters index <https://golangci-lint.run/docs/linters/>

**Revision record** — the mutable sources, as last read. A refresh diffs each against its recorded
revision first, so it reads what changed rather than everything, then updates this table.

| Source | Revision read | Checked |
|---|---|---|
| Go Code Review Comments (`golang/wiki` mirror, `CodeReviewComments.md`) | `228ca0b` (2026-09-01) | 2026-09-09 |
| Google Go Style Guide (`google/styleguide`, `go/`) | `c098353` (2026-03-18) | 2026-09-09 |
| Uber Go Style Guide (`uber-go/guide`) | `1d60a91` (2026-04-15) | 2026-09-09 |
| revive rule descriptions (`mgechev/revive`, `RULES_DESCRIPTIONS.md`) | `803cd04` (2026-09-03) | 2026-09-09 |
| Effective Go, doc comment syntax, `cmd/vet`, package docs | versioned with the Go release — read at go1.27.1 | 2026-09-09 |

**Procedure**

Expand All @@ -105,16 +133,21 @@ citation. Everything the skills assert should be traceable to one of these.
halves: every linter taught in components must be enabled in `references/golangci.v2.yml`,
and — when a floor-minor Go toolchain is on PATH (CI's matrix installs both `1.26.x` and
`1.27.x`; locally it soft-skips with a note) — the `go-idioms` Fixer column is verified against
`go tool fix help`: plain names must be registered, † names must not be. The floor minor
lives in `GO_FLOOR_MINOR` in the script and in the workflow's matrix floor entry (`1.26.x`) — move
all three (docs baseline included) together.
`go tool fix help`: plain names must be registered, † names must not be. An analyzer a skill
teaches as *opt-in* — `shadow` in `go-idioms` — is the deliberate exception to the first half: it
is taught together with the config line that switches it on, and is not added to the reference
config at a refresh. The floor minor lives in `GO_FLOOR_MINOR` in the script and in the
workflow's matrix floor entry (`1.26.x`) — move all three (docs baseline included) together.
**Never hardcode a tool version in a component.** A named `golangci-lint` release rots within
weeks and nobody remembers why it was chosen; the skills carry the *pin policy* (pin exactly, one
source of truth, automated bump PR) plus the changelog URL, and let the consuming repo own the
number. The same goes for `gopls`/`gofumpt` versions outside `docs/install.md`.
5. Keep the two copies of the reference lint config in sync: `references/golangci.v2.yml` and the
scaffold block in `go-lint-setup`.
6. Record the refresh in **CHANGELOG.md** under `## [Unreleased]`.
6. Run `python3 scripts/validate.py --check-links` — every cited URL must still resolve; a moved
page is fixed in the same refresh.
7. Update the **Revision record** above, then record the refresh in **CHANGELOG.md** under
`## [Unreleased]`.

## Dual-host parity

Expand Down
Loading
Loading