Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
64332c4
feat(go-coding): make the router route — mandatory hop table and mini…
sebastian-iancu Sep 3, 2026
23a6f72
feat(skills): concrete trigger words for go-layout, go-concurrency an…
sebastian-iancu Sep 3, 2026
31dcc2d
refactor(skills): merge go-linting into go-lint-setup; keep a depreca…
sebastian-iancu Sep 3, 2026
dd6e071
refactor(skills): go-lint-setup — restore references/ path note, lint…
sebastian-iancu Sep 3, 2026
df9c18e
feat(skills): Go 1.27 support — forward hints in go-idioms, golangci-…
sebastian-iancu Sep 3, 2026
7b48d27
fix(skills): correct pre-release Go 1.27 mentions in go-concurrency/g…
sebastian-iancu Sep 3, 2026
cead11e
fix(docs,skills): Go 1.27 follow-ups — install.md consistency, fixer …
sebastian-iancu Sep 3, 2026
81f3c1b
feat(hooks): session banner names the skill hop and the commands; hoo…
sebastian-iancu Sep 3, 2026
67cfb86
feat(hooks): nudge the matching go-coding skill once per session afte…
sebastian-iancu Sep 3, 2026
f1dcc8d
test(hooks): assert silence as exact emptiness in hooks-test; can-fai…
sebastian-iancu Sep 3, 2026
38b6b86
docs(agent,readme): one review seat per diff; brief templates for orc…
sebastian-iancu Sep 3, 2026
a305725
feat(scripts): usage-report.py — measure skill/agent adoption from lo…
sebastian-iancu Sep 3, 2026
8ad6af9
chore(release): v0.5.0
sebastian-iancu Sep 3, 2026
9ef7aa8
fix(hooks): deliver the skill nudge as a systemMessage; committed can…
sebastian-iancu Sep 3, 2026
43f5dc2
docs: inventory the nudge hook and test harness; re-front go-lint-set…
sebastian-iancu Sep 3, 2026
9be6d9c
fix(hooks): nudge on the edit, not on the whole file
sebastian-iancu Sep 3, 2026
16b7d43
refactor(skills)!: remove go-linting and go-explain
sebastian-iancu Sep 3, 2026
4d2a4d6
refactor(skills): tighten descriptions; plain English when a person r…
sebastian-iancu Sep 3, 2026
b43f755
docs(changelog): shorten the 0.5.0 entries
sebastian-iancu Sep 3, 2026
92bfcff
docs(testing): the nudge check covers an edit that does not touch the…
sebastian-iancu Sep 3, 2026
cdac198
feat(rule,validate): bring the Cursor rule level with the router; che…
sebastian-iancu Sep 3, 2026
ee312c1
fix(hooks,skills): classify the added text only; correct four Go 1.27…
sebastian-iancu Sep 3, 2026
20f7a7d
fix(docs,validate): review nits — stale inventories, gopls pin, self-…
sebastian-iancu Sep 3, 2026
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
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "go-coding",
"version": "0.4.1",
"version": "0.5.0",
"description": "Idiomatic Go coding standards for AI assistants — formatting, errors, concurrency, testing, layout.",
"author": {
"name": "Cadasto B.V.",
Expand Down
2 changes: 1 addition & 1 deletion .cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "go-coding",
"version": "0.4.1",
"version": "0.5.0",
"description": "Idiomatic Go coding standards for AI assistants — formatting, errors, concurrency, testing, layout.",
"author": {
"name": "Cadasto B.V.",
Expand Down
16 changes: 13 additions & 3 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,28 @@ on:
jobs:
validate:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
go-version: ['1.26.x', '1.27.x']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.x'
# The floor-minor Go toolchain activates the validator's Fixer-column check
# (go tool fix help is the authority for what `go fix` ships). Keep this minor
# The floor-minor (1.26.x) leg activates the validator's Fixer-column check
# (go tool fix help is the authority for what `go fix` ships); keep that minor
# in step with GO_FLOOR_MINOR in scripts/validate.py and the documented baseline.
# The 1.27.x leg proves the plugin also validates on the next Go version — its
# Fixer-column check soft-skips (a note, not a failure) since it isn't the floor.
- uses: actions/setup-go@v5
with:
go-version: '1.26.x'
go-version: ${{ matrix.go-version }}
cache: false # no go.mod — nothing to cache
# CI is strict and deterministic: Python is guaranteed here, so run the
# validator directly (the scripts/validate.sh graceful skip is for local use).
- run: python3 scripts/validate.py
# A green validator proves the tree is valid, not that the checks still check.
- run: python3 scripts/validate.py --selftest
# Bash-only hook test harness; runs on both matrix legs.
- run: ./scripts/hooks-test.sh
28 changes: 15 additions & 13 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This file provides guidance to AI coding assistants (Claude Code, Cursor, and co

The **Go Coding Plugin** is an AI plugin by Cadasto B.V. that teaches AI coding assistants **idiomatic Go coding standards** — formatting, naming, error handling, concurrency, testing, and project layout — through skills, commands, agents, hooks, and Cursor rules. It targets **both Claude Code and Cursor** from a single shared component set.

> **Current status — v0.4.0.** A complete dual-host (Claude Code + Cursor) Go-standards set, baselined on **Go 1.26.4+** as a hard floor (no fallback guidance for 1.25 or older; version annotations remain as provenance), that validates clean (`./scripts/validate.sh` + `claude plugin validate .`): the auto-invoked `go-coding` **router** skill; the focused standards skills `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-linting`, `go-layout`; the read-only `go-reviewer` agent; the user-invoked `/go-explain` and `/go-lint-setup` skills; a shipped `references/golangci.v2.yml`; the `rules/go-context.mdc` Cursor rule; and host-agnostic `session-start` + `format-on-save` hooks. Do not assume a file is present because it is documented here — check first.
> **Current status — v0.5.0.** A complete dual-host (Claude Code + Cursor) Go-standards set, baselined on **Go 1.26.4+** (Go 1.27 supported; its additions are flagged as hints) as a hard floor (no fallback guidance for 1.25 or older; version annotations remain as provenance), that validates clean (`./scripts/validate.sh` + `claude plugin validate .`): the auto-invoked `go-coding` **router** skill; the focused standards skills `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-layout`; the report-only `go-reviewer` agent; the user-invoked `/go-lint-setup` skill; a shipped `references/golangci.v2.yml`; the `rules/go-context.mdc` Cursor rule; and host-agnostic `session-start` + `format-on-save` + `skill-nudge` hooks. Do not assume a file is present because it is documented here — check first.

## Domain Context

Expand All @@ -30,25 +30,26 @@ When a recommendation derives from one of the above, attribute it explicitly and
This repo supports **both Claude Code and Cursor**. Shared assets (skills, commands, agents) are consumed by both hosts; host-specific manifests and hook configs are kept separate.

- **Claude manifest**: `.claude-plugin/plugin.json` — `name`, `version`, `description`, `author` (an **object** `{name, url}` — `claude plugin validate` rejects a string), `license`, `repository`, `keywords`. Claude Code discovers components from the **default folders** (`skills/`, `commands/`, `agents/`, `hooks/`) automatically; no explicit path map is needed.
- **Cursor manifest**: `.cursor-plugin/plugin.json` — same metadata **plus** explicit top-level path keys (`skills`, `rules`, `agents`, `commands`, `hooks`). No `mcpServers` — this plugin has no MCP backend. Keep `name`/`version`/`description`/`author` identical to the Claude manifest.
- **Skills**: `skills/<name>/SKILL.md` — shared by both hosts. Shipped: `go-coding` (auto-invoked router) plus the focused, load-on-use `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-linting`, `go-layout` standards skills.
- **Slash commands** are authored as **user-invoked skills** (`skills/<name>/SKILL.md` with `argument-hint` + `allowed-tools`), not the legacy `commands/` folder — both yield a `/<name>` command, but the skills layout is preferred (current `plugin-dev` guidance). Keep the surface small; put multi-step workflows in auto-invoked skills. Shipped: `/go-explain` (idiom/standard lookup) and `/go-lint-setup` (scaffold the golangci-lint v2 config).
- **Agents**: `agents/<name>.md` — context-isolated specialists. Shipped: `go-reviewer` (read-only Go diff/file reviewer applying the review-heuristics catalog; `tools:` not `allowed-tools:`).
- **Cursor manifest**: `.cursor-plugin/plugin.json` — same metadata **plus** explicit top-level path keys — `skills`, `agents`, `rules`, `hooks` (a `commands` key would go here too, but this plugin ships no `commands/` folder: `/go-lint-setup` is a user-invoked skill). No `mcpServers` — this plugin has no MCP backend. Keep `name`/`version`/`description`/`author` identical to the Claude manifest.
- **Skills**: `skills/<name>/SKILL.md` — shared by both hosts. Shipped: `go-coding` (auto-invoked router) plus the focused, load-on-use `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-layout` standards skills. `go-linting` was merged into `go-lint-setup` and removed in 0.5.0.
- **Slash commands** are authored as **user-invoked skills** (`skills/<name>/SKILL.md` with `argument-hint` + `allowed-tools`), not the legacy `commands/` folder — both yield a `/<name>` command, but the skills layout is preferred (current `plugin-dev` guidance). Keep the surface small; put multi-step workflows in auto-invoked skills. Shipped: `/go-lint-setup` (scaffold the golangci-lint v2 config). `/go-explain` was removed in 0.5.0 — a one-shot lookup the focused skills already answer.
- **Agents**: `agents/<name>.md` — context-isolated specialists. Shipped: `go-reviewer` (report-only Go diff/file reviewer applying the review-heuristics catalog; `tools:` not `allowed-tools:`).
- **Cursor rules**: `rules/*.mdc` — Cursor-only rule guidance with frontmatter (`description`, `alwaysApply`, `globs`, e.g. `globs: ["**/*.go"]`), referenced by the Cursor manifest's `rules` path. Shipped: `rules/go-context.mdc` (mirrors the `go-coding` router).
- **Claude hooks**: `hooks/hooks.json` — object `{ "hooks": { "SessionStart": [...], "PostToolUse": [...] } }`; use `${CLAUDE_PLUGIN_ROOT}` in command paths. Present — wires `session-start.sh` (`SessionStart`) and `format-on-save.sh` (`PostToolUse`, `matcher: "Write|Edit"`).
- **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` (`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. Both host-agnostic so either manifest can invoke them. Present.
- **Claude hooks**: `hooks/hooks.json` — object `{ "hooks": { "SessionStart": [...], "PostToolUse": [...] } }`; use `${CLAUDE_PLUGIN_ROOT}` in command paths. Present — wires `session-start.sh` (`SessionStart`) and `format-on-save.sh` + `skill-nudge.sh` (`PostToolUse`, `matcher: "Write|Edit"`).
- **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), 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 installs `1.26.x`, locally it soft-skips) 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`), 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.
- **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

The full component surface — all shipped:
The full component surface:

- **Skills** — *shipped*: `go-coding` (auto-invoked router) + `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-linting`, `go-layout`. Each routes deeper topics to the enforcing tool and cites authoritative sources.
- **Slash commands** — *shipped* as user-invoked skills: `/go-explain` (idiom/standard lookup) and `/go-lint-setup` (scaffold the golangci-lint v2 config).
- **Agent** — *shipped*: `go-reviewer`, a context-isolated, read-only reviewer applying the review-heuristics catalog (no sub-agent dispatch; treats the diff as untrusted content).
- **Skills** — *shipped*: `go-coding` (auto-invoked router) + `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-layout`. Each routes deeper topics to the enforcing tool and cites authoritative sources.
- **Slash commands** — *shipped* as user-invoked skill: `/go-lint-setup` (scaffold the golangci-lint v2 config).
- **Removed in 0.5.0** — `go-linting` (merged into `go-lint-setup`) and `/go-explain` (a one-shot lookup the focused skills already answer). Do not re-add either; route the topic instead.
- **Agent** — *shipped*: `go-reviewer`, a context-isolated, report-only reviewer applying the review-heuristics catalog (no sub-agent dispatch; treats the diff as untrusted content).
- **Cursor rule** — *shipped*: `rules/go-context.mdc`, scoped to `**/*.go`, mirroring the `go-coding` router for Cursor.

## Development
Expand All @@ -59,6 +60,7 @@ No build step — the plugin is pure Markdown + JSON. Validate and dogfood local

```bash
./scripts/validate.sh # dual-host parity / frontmatter (soft-skips if no python3)
./scripts/hooks-test.sh # bash tests for hooks/session-start.sh + hooks/skill-nudge.sh
claude plugin validate . # manifest + component structure (no extra deps)
claude --plugin-dir /path/to/go-coding-plugin # load locally for one session (dogfooding)
```
Expand Down
66 changes: 66 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,72 @@ 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

## [0.5.0] - 2026-09-03

Makes the `go-coding` router route. A usage analysis of local session transcripts found the router
loading often and the focused skills almost never, so this release adds a hop table, a post-edit
nudge, trigger-first descriptions and a banner that names the next step. It also shrinks the
surface — `go-linting` merged into `go-lint-setup`, `/go-explain` removed — adds Go 1.27 support on
the existing Go 1.26.4+ floor, and ships a script for measuring adoption.

### Added
- Skill `go-coding` — a "Route, then load" table mapping diff content to the skill to load, and a
minimum checklist for when a second load is not affordable.
- Skill `go-coding`, agent `go-reviewer` — "Writing for the human": anything a person reads (PR
text, review findings, a question) states the effect before the mechanism, in plain English, short.
- Hook `hooks/skill-nudge.sh` — after a Go edit, names one skill the edit calls for. Under Claude
Code it matches only the text the edit adds (`tool_input.new_string`, or `content` for a write),
not the file and not the deleted text; Cursor passes a path alone, so there it matches the file
and says so. Once per skill per session, at most three per session; a `systemMessage` under
Claude Code, a plain line under Cursor.
- Script `scripts/hooks-test.sh` — 28 bash tests over all three hooks, on production-shaped
payloads, asserting exit status as well as output, with can-fail controls proving the silence
assertions can actually fail. Runs in CI.
- Script `scripts/usage-report.py` — stdlib-only adoption report from local session transcripts;
counting rules and the 50% target in `docs/testing.md`.
- Docs `README.md` — implementer and reviewer brief templates for orchestrators, since a subagent
does not inherit the parent session's skills.
- Skills `go-idioms`, `go-lint-setup` — Go 1.27 hints (generic methods, json/v2-backed
`encoding/json`, the four new `go fix` modernizers, `stdversion` by default under `go test`) and
the golangci-lint ≥ v2.13.0 floor for Go 1.27.
- CI `.github/workflows/validate.yml` — Go matrix `1.26.x` + `1.27.x`, `fail-fast: false`; the
floor leg keeps the strict `go-idioms` Fixer-column check.
- Validation `scripts/validate.py` — hook parity (the same script wired for the equivalent event on
both hosts, existing and executable, none left unwired) and doc component inventories (every
shipped skill, agent and hook named where the docs claim to list them).
- Validation `scripts/validate.py --selftest` — rebuilds each structural check's failure case in a
temporary tree and requires the check to catch it, and to stay quiet once the defect is removed.
Runs in CI, because a green run over a valid tree says nothing about whether a check still checks.

### Changed
- Skills — descriptions rewritten trigger-first and shortened 10% (4,619 → 4,163 characters).
Always-on context competes with the session's real work. `go-idioms` in particular no longer
triggers on "writes or reviews Go", which was nearly every Go turn.
- Skill `go-lint-setup` — absorbs `go-linting`'s config-schema, adoption and upgrade-breakage
content; re-fronted as "scaffold, adopt, or debug".
- Hook `hooks/session-start.sh` — the banner names the hop and the focused skills, and offers
`/go-lint-setup` only when the workspace has no golangci-lint config.
- Agent `go-reviewer`, skill `go-coding` — one review seat per diff: where a workflow already has a
reviewer, that reviewer loads the skills itself instead of `go-reviewer` being dispatched beside it.
- Cursor rule `rules/go-context.mdc` — brought level with the router: the diff→skill mapping, the
minimum checklist, and the plain-English rule for anything a person reads. Drops the Claude-only
`${CLAUDE_PLUGIN_ROOT}` reference from a Cursor-only file.
- Skills `go-idioms`, `go-testing` — four Go 1.27 claims corrected against their sources: v1
`encoding/json` stays the default (the release notes say users are not required to migrate);
`embedlit` folds a promoted field into the parent literal rather than a post-literal assignment;
`unsafefuncs` gains the table row its prose already assumed; `stdversion` is dated to when `go
test` starts running it by default, not to the check's existence. `httptest.NewTestServer` now
carries its signature.
- Docs `docs/install.md` — `gopls` pin moves to v0.23.x, the line that adds Go 1.27 support.
- Docs `docs/testing.md` — adds the missing `format-on-save` triggering check.
- Skills, agent, Cursor rule, docs — Go 1.26.4+ remains the hard floor; Go 1.27 is supported and its
additions are flagged as hints. `docs/install.md` recommends the latest 1.27.x patch.

### Removed
- Skill `go-linting` — merged into `go-lint-setup`, the skill the router and banner point at.
- Skill `/go-explain` — one-shot lookups are what the focused skills already do, with the same
citations and the code in view.

## [0.4.1] - 2026-08-25

Corrects three component defects and the docs that described them: a `PostToolUse` hook timeout that was five hours rather than twenty seconds, a reviewer agent calling itself read-only while holding `Bash`, and `go-lint-setup` offering a migration it had no tool grant to run.
Expand Down
Loading
Loading