diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 120c1ff..dddacb9 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -10,5 +10,5 @@ - [ ] Cursor install tested locally when manifest, rule, or hook content changed (see [docs/install.md](../docs/install.md#cursor)) - [ ] Both manifests kept in sync when metadata changed: `.claude-plugin/plugin.json` and `.cursor-plugin/plugin.json` - [ ] Cursor rule files and the `.cursor-plugin/plugin.json` path map kept in step with the components that exist -- [ ] Version bumped and [CHANGELOG.md](../CHANGELOG.md) updated (if component content changed) — see [docs/versioning.md](../docs/versioning.md) +- [ ] Version bumped and [CHANGELOG.md](../CHANGELOG.md) updated (if component content changed); see [docs/versioning.md](../docs/versioning.md) - [ ] Docs synced (AGENTS.md, README.md, hooks/session-start.sh) when components were added or renamed diff --git a/AGENTS.md b/AGENTS.md index 3a5f123..6013844 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,107 +4,129 @@ This file provides guidance to AI coding assistants (Claude Code, Cursor, and co ## Project Overview -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. +The **Go Coding Plugin** (`go-coding`) is an AI plugin by Cadasto B.V. that teaches AI coding assistants **idiomatic Go coding standards** (formatting, naming, error handling, concurrency, testing, project layout) through skills, agents, hooks, and a Cursor rule. It targets **both Claude Code and Cursor** from a single shared component set. The human pitch is in [README.md](README.md); the shipped version is in the manifests and [CHANGELOG.md](CHANGELOG.md). -> **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. +Out of scope: there is **no companion MCP server** and no `commands/` folder. Do not assume a file is present because it is documented here; check first. + +Detail lives in `docs/`; keep a one-line rule here and point to the doc that owns it: + +| Document | Owns | +|----------|------| +| [docs/install.md](docs/install.md) | Claude Code and Cursor install, local `--plugin-dir` loading, host toolchain, hooks | +| [docs/testing.md](docs/testing.md) | What each validator checks; the manual triggering tests; adoption measurement | +| [docs/versioning.md](docs/versioning.md) | SemVer rules, release steps, the marketplace repin | +| [docs/authoring.md](docs/authoring.md) | Component naming, descriptions, the standards source registry, dual-host parity | ## Domain Context This plugin encodes **Go (golang) coding standards**. Guidance must be grounded in authoritative, verifiable sources rather than personal preference: -- **Formatting** — `gofmt` is the canonical formatter; `gofumpt` is a stricter superset. Formatting is non-negotiable and machine-enforced, not a matter of opinion. -- **Vetting & static analysis** — `go vet` (suspicious constructs in the toolchain), `staticcheck`, and `golangci-lint` (the de-facto meta-linter that aggregates many analyzers). +- **Baseline**: **Go 1.26.4+** is a hard floor (Go 1.27 supported; its additions are flagged as hints). No fallback guidance for 1.25 or older; version annotations remain as provenance. +- **Formatting**: `gofmt` is the canonical formatter; `gofumpt` is a stricter superset. Formatting is non-negotiable and machine-enforced, not a matter of opinion. +- **Vetting & static analysis**: `go vet` (suspicious constructs in the toolchain), `staticcheck`, and `golangci-lint` (the de-facto meta-linter that aggregates many analyzers). - **Style references** (cite these when a rule depends on them): - - **Effective Go** — - - **Go Code Review Comments** — - - **Google Go Style Guide** — — 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** — - - **Linter rule catalogues** — name the rule when a skill says a tool catches something: `go vet` , staticcheck , revive -- **Standard library & toolchain** — package docs at ; modules, `go test`, table-driven tests, and the race detector (`go test -race`) are the baseline testing conventions. + - **Effective Go**: + - **Go Code Review Comments**: + - **Google Go Style Guide**: . 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**: + - **Linter rule catalogues**: name the rule when a skill says a tool catches something: `go vet` , staticcheck , revive +- **Standard library & toolchain**: package docs at ; 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. -**Refreshing the skills against current Go practice** (e.g. "check current Go best practices and update the skills"): follow the **source registry and procedure** in [docs/authoring.md](docs/authoring.md#refreshing-the-standards-baseline-source-registry) — it lists every source to re-read, in order, plus the version-gating rules. Re-read them; never refresh from memory. Two recurring traps: the *released* Go version is not whatever `go.dev/doc/go1.NN` renders (check the release history), and the stdlib APIs a skill is missing are usually the ones that landed *after* it was written. - -## Repository Layout - -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`, `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//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//SKILL.md` with `argument-hint` + `allowed-tools`), not the legacy `commands/` folder — both yield a `/` 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/.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` + `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), 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.) +**Advice == tooling.** Every linter taught in a component must be 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. The `go-idioms` Fixer column must match `go tool fix help` on the floor-minor toolchain. The Google readability tie-break sentence must read identically in the `go-coding` router, `rules/go-context.mdc`, and `go-reviewer`. `scripts/validate.py` enforces all three. -### Component surface +**Refreshing the skills against current Go practice** (e.g. "check current Go best practices and update the skills"): follow the **source registry and procedure** in [docs/authoring.md](docs/authoring.md#refreshing-the-standards-baseline-source-registry). It lists every source to re-read, in order, plus the version-gating rules. Re-read them; never refresh from memory. Two recurring traps: the *released* Go version is not whatever `go.dev/doc/go1.NN` renders (check the release history), and the stdlib APIs a skill is missing are usually the ones that landed *after* it was written. -The full component surface: +## Repository Layout -- **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. +Shared assets (skills, 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** automatically; no explicit path map is needed. +- **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 if a `commands/` folder ever shipped). No `mcpServers`. Keep `name`/`version`/`description`/`author` identical to the Claude manifest. +- **Skills**: `skills//SKILL.md`, shared by both hosts, including user-invoked slash commands. +- **Agents**: `agents/.md`, context-isolated specialists. +- **Cursor rules**: `rules/*.mdc`, Cursor-only, with frontmatter (`description`, `alwaysApply`, `globs`, e.g. `globs: ["**/*.go"]`), referenced by the Cursor manifest's `rules` path. +- **Claude hooks**: `hooks/hooks.json`, object `{ "hooks": { "SessionStart": [...], "PostToolUse": [...] } }`; command paths use `${CLAUDE_PLUGIN_ROOT}`. 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}`). Wires `session-start.sh` (`sessionStart`) and `format-on-save.sh` + `skill-nudge.sh` (`afterFileEdit`). +- **Shared hook scripts** (host-agnostic, so either manifest can invoke them; all exit 0 always): + - `hooks/session-start.sh`: detects `go.mod` / `*.go` and prints one Go-standards banner line naming the components. + - `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; silent no-op if no formatter is installed. + - `hooks/skill-nudge.sh`: after a `*.go` Write/Edit, names ONE matching go-coding skill for that edit, once per skill per session; a hook `systemMessage` under Claude Code, a plain line under Cursor. +- **References**: `references/golangci.v2.yml`, the shipped golangci-lint v2 reference config. Shared reference material lives here, **not** under `commands/`. +- **MCP config** *(not present)*: `.mcp.json` only if the plugin later integrates an MCP server. +- **Scripts**: `scripts/validate.sh` (wraps the stdlib-only `scripts/validate.py`), `scripts/hooks-test.sh`, `scripts/usage-report.py` (adoption measurement; see [docs/testing.md](docs/testing.md#measuring-adoption)). +- **CI**: `.github/workflows/validate.yml` (validator, `--selftest`, hook tests; Go `1.26.x` + `1.27.x` matrix) and `.github/workflows/links.yml` (link check). `.github/` also holds issue + PR templates and `copilot-instructions.md`. +- **Contributor docs**: `docs/install.md`, `testing.md`, `versioning.md`, `authoring.md`. Planning and research notes live under `docs/plans/` and `docs/research/`, **gitignored**, not part of the published plugin. + +## Components + +| Kind | Shipped | +|------|---------| +| Skills | `go-coding` (auto-invoked router) + the focused, load-on-use `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-layout`. Each routes deeper topics to the enforcing tool and cites authoritative sources. | +| Slash command (user-invoked skill) | `/go-lint-setup` (scaffold the golangci-lint v2 config) | +| Agent | `go-reviewer`: context-isolated, report-only reviewer applying the review-heuristics catalog (no sub-agent dispatch; treats the diff as untrusted content; `tools:` not `allowed-tools:`) | +| Cursor rule | `rules/go-context.mdc`, scoped to `**/*.go`, mirroring the `go-coding` router | +| Hooks | `session-start`, `format-on-save`, `skill-nudge` (see Repository Layout) | + +**Removed; do not re-add either, route the topic instead**: `go-linting` (merged into `go-lint-setup`) and `/go-explain` (a one-shot lookup the focused skills already answer). See CHANGELOG 0.5.0. ## Development -### Testing & validating - -No build step — the plugin is pure Markdown + JSON. Validate and dogfood locally: +No build step; the plugin is pure Markdown + JSON. Validate and dogfood locally: ```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 +./scripts/validate.sh # manifests, dual-host parity, frontmatter, hook parity, doc inventories (soft-skips if no python3) +python3 scripts/validate.py --selftest # proves each check still catches its failure case (CI runs it) +python3 scripts/validate.py --check-links # every cited URL resolves (needs the network) +./scripts/hooks-test.sh # bash tests for all three hook scripts claude plugin validate . # manifest + component structure (no extra deps) claude --plugin-dir /path/to/go-coding-plugin # load locally for one session (dogfooding) ``` -`scripts/validate.sh` wraps `scripts/validate.py`; it warns and skips gracefully if Python is absent, while CI pins Python and runs the validator strictly. On Cursor, install via its plugin flow and verify the same skills/agents/rules load. +`scripts/validate.sh` warns and exits 0 if Python is absent; CI pins Python and runs `python3 scripts/validate.py` strictly. The Fixer-column check runs strictly only with a floor-minor (`1.26.x`) Go on PATH and soft-skips on other minors. What each check covers is in [docs/testing.md](docs/testing.md#validation). On Cursor, install via its plugin flow and verify the same skills/agents/rules load. ### File Conventions -- Skills go in `skills//SKILL.md` — this includes user-invoked slash commands (`/`, carrying `argument-hint`/`allowed-tools`); agents in `agents/.md`. The legacy `commands/.md` layout is not used. +- Skills go in `skills//SKILL.md`, including user-invoked slash commands (`/`, carrying `argument-hint`/`allowed-tools`); agents in `agents/.md`. The legacy `commands/.md` layout is not used; both yield a `/` command, but the skills layout is preferred (current `plugin-dev` guidance). Keep the command surface small; put multi-step workflows in auto-invoked skills. - All Markdown component files use **YAML frontmatter** for metadata. - Use **kebab-case** for all directory and file names. -- `allowed-tools:` (skills/commands) pre-approves tools to avoid permission prompts; **agents use `tools:` instead** — `allowed-tools:` in an agent file is silently ignored and the agent inherits *all* tools. +- `allowed-tools:` (skills/commands) pre-approves tools to avoid permission prompts; **agents use `tools:` instead**. - Skills: declare auto-invocable / user-invocable intent in frontmatter; load the authoritative standard before acting. - User-invoked skills (slash commands): set `argument-hint` and `allowed-tools` in frontmatter and use `$ARGUMENTS` in the body; keep instructions concise for single-interaction completion. -- Use `${CLAUDE_PLUGIN_ROOT}` for intra-plugin paths in Claude hook/MCP command fields — never hardcode absolute paths or `~`. -- Contributor reference, plans, and design docs go in `docs/`. Shared command reference material goes in a top-level `references/` dir, **not** under `commands/` (host validators treat every `commands/**/*.md` as a command and warn on missing frontmatter). +- Use `${CLAUDE_PLUGIN_ROOT}` for intra-plugin paths in Claude hook/MCP command fields; never hardcode absolute paths or `~`. +- Contributor reference, plans, and design docs go in `docs/`. Full authoring conventions: [docs/authoring.md](docs/authoring.md). ### Documentation Sync -When adding or renaming components, update in lockstep: **AGENTS.md** (the layout / component sections), **README.md**, and the session-start hook's "Available: …" list. Cursor uses the same skills/agents/rules paths, so no separate Cursor-only list is needed — but the **Cursor rule files and the `.cursor-plugin/plugin.json` path map** must stay in step with what exists. - -### Versioning - -- Keep `version` (and, for consistency, `description` and `author`) **in sync across both** `.claude-plugin/plugin.json` and `.cursor-plugin/plugin.json`. -- Follow **Semantic Versioning**; update both manifests and **CHANGELOG.md** (Keep a Changelog format) when releasing. See [docs/versioning.md](docs/versioning.md). +When adding or renaming components, update in lockstep: **AGENTS.md** (the layout / component sections), **README.md**, **docs/testing.md**, and the component list in the session-start banner (`hooks/session-start.sh`); hooks also in **docs/install.md**. The validator fails if a shipped skill, agent or hook is missing from these docs. Cursor uses the same skills/agents/rules paths, so no separate Cursor-only list is needed, but the **Cursor rule files and the `.cursor-plugin/plugin.json` path map** must stay in step with what exists. ### CHANGELOG style - Entries accumulate under `## [Unreleased]` and fold into the next `## [X.Y.Z] - YYYY-MM-DD` section at release. -- Use the Keep a Changelog groups in order — **Added, Changed, Deprecated, Removed, Fixed, Security** — omitting empty groups. -- One terse line per bullet; lead with the subsystem (`Skills:`, `Commands:`, `Cursor rule :`) and use backticks for file/command/tool/frontmatter-key names. No rationale or PR links — that belongs in commit messages. +- Use the Keep a Changelog groups in order (**Added, Changed, Deprecated, Removed, Fixed, Security**), omitting empty groups. +- One terse line per bullet; lead with the subsystem (e.g. `Skills:`, `Agents:`, `Hooks:`, `Docs:`, `Cursor rule :`) and use backticks for file/command/tool/frontmatter-key names. No rationale or PR links; that belongs in commit messages. -### Commit Messages & Branching +### Commit Messages -- Follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), e.g. `feat(skills): add go-coding awareness skill`, `fix(commands): correct allowed-tools`. +- Follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), e.g. `feat(skills): add go-coding awareness skill`, `fix(hooks): correct the matcher`; the release commit is `chore(release): vX.Y.Z`. - Scopes: `skills`, `commands`, `agents`, `hooks`, `rules`, `docs`. -- Use feature branches and pull requests; PR validation runs on every push. + +### Versioning + +- Keep `version` (and `description` and `author`) **in sync across both** manifests; the validator enforces parity. +- Follow **Semantic Versioning**; update both manifests and **CHANGELOG.md** when releasing. Bump rules and release steps: [docs/versioning.md](docs/versioning.md). + +### Branching + +- Use feature branches and pull requests. CI (`validate.yml`) runs on every pull request and on pushes to `main`. ## Gotchas -- **Agents use `tools:`, not `allowed-tools:`.** In an agent file `allowed-tools:` is ignored and the agent silently inherits *all* tools. Use `tools:` (a YAML list). -- **Keep the two manifests in parity.** Cursor needs explicit path keys (`skills`/`rules`/`agents`/`commands`/`hooks`); Claude relies on default-folder discovery. A component added for one host but missing from the other's manifest (or rule map) will silently not load there. +- **Agents use `tools:`, not `allowed-tools:`.** In an agent file `allowed-tools:` is ignored and the agent silently inherits *all* tools. Use `tools:` (a YAML list). The validator flags it as an error. +- **Keep the two manifests in parity.** Cursor needs explicit path keys; Claude relies on default-folder discovery. A component added for one host but missing from the other's manifest (or rule map) will silently not load there. - **The Cursor hook uses a workspace-relative command** (`bash hooks/session-start.sh`), *not* `${CLAUDE_PLUGIN_ROOT}` (a Claude-Code-only variable). Keep both hook configs in step; don't "fix" the Cursor one to use the variable. +- **Every hook script must be wired on both hosts.** The validator requires each `hooks/*.sh` to be wired for the equivalent event on both hosts, exist, and be executable; none may be left unwired. - **Shared command references live in top-level `references/`, not under `commands/`.** `claude plugin validate` treats every `commands/**/*.md` as a command and warns on missing frontmatter. - **Don't invent a companion MCP server.** This plugin has no MCP backend today; `.mcp.json` should only appear if one is genuinely added. -- **Register in the marketplace separately — and repin it on every release.** Public availability requires an entry in the `cadasto` marketplace, maintained in `Cadasto/plugin-marketplace`. That entry is pinned to a release tag, so tagging here ships nothing until the entry's `version` and `source.ref` are bumped; see [docs/versioning.md](docs/versioning.md#marketplace). +- **Register in the marketplace separately, and repin it on every release.** Public availability requires an entry in the `cadasto` marketplace, maintained in `Cadasto/plugin-marketplace`. That entry is pinned to a release tag, so tagging here ships nothing until the entry's `version` and `source.ref` are bumped; see [docs/versioning.md](docs/versioning.md#marketplace). diff --git a/CHANGELOG.md b/CHANGELOG.md index 33c247b..37824bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,15 @@ # Changelog -All notable changes to this project will be documented in this file. +All notable changes to this project are documented in this file. -The format is based on Keep a Changelog, and this project adheres to Semantic Versioning. - -- Keep a Changelog: https://keepachangelog.com/en/1.1.0/ -- Semantic Versioning: https://semver.org/spec/v2.0.0.html +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- Docs: `README.md` follows the shared Cadasto plugin layout (badge row, requirements, table of contents, features); each `docs/` page opens with a paragraph naming its reader. +- Docs: `docs/versioning.md` release steps include updating the README version badge. + ## [0.6.0] - 2026-09-09 ### Added diff --git a/README.md b/README.md index 0d57df9..6978071 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,68 @@ # Go Coding Plugin -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, an agent, three hooks (session-start, format-on-save, skill-nudge), and a Cursor rule. It targets **both Claude Code and Cursor** from a single shared component set. +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) +[![Version](https://img.shields.io/badge/version-0.6.0-blue)](CHANGELOG.md) +[![Claude Code](https://img.shields.io/badge/Claude_Code-plugin-D97757?logo=anthropic&logoColor=white)](https://docs.claude.com/en/docs/claude-code/overview) +[![Cursor](https://img.shields.io/badge/Cursor-plugin-000?logo=cursor&logoColor=white)](https://cursor.com) +[![Keep a Changelog](https://img.shields.io/badge/Keep%20a%20Changelog-1.1.0-E05735)](CHANGELOG.md) -## Install +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. It adds skills, an agent, and three hooks (session-start, format-on-save, skill-nudge) for **[Claude Code](https://docs.claude.com/en/docs/claude-code/overview)** and **[Cursor](https://cursor.com)** from one shared component set, plus a Cursor rule. -**Claude Code** — from the Cadasto marketplace: +The plugin owns the judgement layer of Go standards. Formatting, vetting and linting stay with the deterministic tools (`gofmt`/`gofumpt`, `go vet`, `staticcheck`, `golangci-lint`, `go test -race`): each skill names the tool that enforces a rule and cites the source a judgement rule comes from, and the `go-reviewer` agent reports what those tools miss. It covers Go only and carries no business rules. -``` +**Requirements.** A Claude Code or Cursor host. The plugin is pure Markdown + JSON, with no build step and no MCP server, and it installs without a Go toolchain. Its hooks and enforcement guidance expect **Go 1.26.4+** (Go 1.27 supported; its additions are flagged as hints) plus `gofmt`, `gofumpt`, `goimports`, and `gopls` on the host `PATH`, and golangci-lint v2 (v2.13.0 or newer on Go 1.27) for full-tree linting. See [Host toolchain (minimal requirements)](docs/install.md#host-toolchain-minimal-requirements) for what each tool drives and copy-paste install commands. + +## Table of contents + +- [Features](#features) +- [Installation](#installation) +- [Components](#components) +- [Using with subagent orchestrators](#using-with-subagent-orchestrators) +- [Development](#development) +- [Documentation](#documentation) +- [License](#license) + +## Features + +- **Routing:** the auto-invoked `go-coding` router sends each Go topic to the enforcing tool, then to the focused skill that owns it. +- **Focused standards:** `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, and `go-layout` load on use, with each rule cited and framed around the linter that enforces it. +- **Linter setup:** `/go-lint-setup` scaffolds, adopts, or debugs a golangci-lint v2 config, based on the shipped `references/golangci.v2.yml`. +- **Review:** the report-only `go-reviewer` agent returns severity-ranked findings for what linters miss. +- **Format on save:** a hook runs `gofumpt -w` (or `gofmt -w -s`) on each edited `*.go` file. +- **Skill nudges:** after a `*.go` edit, a hook names one matching skill, once per skill per session. +- **Cursor parity:** Cursor gets the same skills, agent, and hooks, plus `rules/go-context.mdc` mirroring the router. + +## Installation + +**Claude Code**: from the Cadasto marketplace: + +```text /plugin marketplace add Cadasto/plugin-marketplace /plugin install go-coding@cadasto ``` Or load a local working copy for a single session: `claude --plugin-dir /path/to/go-coding-plugin`. -**Cursor**: add this repository as a plugin (Settings → Plugins). See [`docs/install.md`](docs/install.md) for both hosts. +**Cursor**: add this repository as a plugin (Settings → Plugins, from a Git URL or a local path). The repo includes a Cursor manifest at [`.cursor-plugin/plugin.json`](.cursor-plugin/plugin.json); skills, agents, and hook scripts are shared with the Claude plugin. -**Prerequisites** — the plugin installs without a Go toolchain, but its hooks and enforcement guidance expect **Go 1.26.4+** (Go 1.27 supported; its additions are flagged as hints) plus `gofmt`, `gofumpt`, `goimports`, and `gopls` on the host `PATH`. See [Host toolchain (minimal requirements)](docs/install.md#host-toolchain-minimal-requirements) for what each tool drives and copy-paste install commands. +See [docs/install.md](docs/install.md) for marketplace, local-development, update, and Cursor install details. -## Component surface +## Components | Component | Status | Purpose | |-----------|--------|---------| | Skill `go-coding` | shipped | Auto-invoked router: sends each Go topic to the enforcing tool and the focused skill below; recommends `gopls-lsp`. | | Session-start hook | shipped | Detects a Go workspace (`go.mod`/`*.go`) and prints one standards line; dual-host. | | Format-on-save hook | shipped | After each `Write`/`Edit` of a `*.go` file, runs `gofumpt -w` (or `gofmt -w -s`) on it; dual-host, host-only, silent no-op if no formatter is installed. | -| Skill-nudge hook | shipped | After each `Write`/`Edit` of a `*.go` file, names ONE matching go-coding skill for that edit, once per skill per session; dual-host — delivered as a hook `systemMessage` under Claude Code, a plain line under Cursor. | -| Skills `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-layout` | shipped | Load-on-use standards — each rule cited, framed around the enforcing linter (`modernize`, `errorlint`, `-race`, …). `go-layout` also owns naming, doc comments, and exported-API shape. | +| Skill-nudge hook | shipped | After each `Write`/`Edit` of a `*.go` file, names ONE matching go-coding skill for that edit, once per skill per session; dual-host: delivered as a hook `systemMessage` under Claude Code, a plain line under Cursor. | +| Skills `go-errors`, `go-concurrency`, `go-testing`, `go-idioms`, `go-layout` | shipped | Load-on-use standards, each rule cited and framed around the enforcing linter (`modernize`, `errorlint`, `-race`, …). `go-layout` also owns naming, doc comments, and exported-API shape. | | Agent `go-reviewer` | shipped | Report-only, context-isolated Go reviewer for what linters miss; severity-ranked findings, no sub-agent dispatch. Its grant excludes `Write`/`Edit` but includes `Bash` to run the linters, so no-edit is a contract it keeps rather than a sandbox that enforces it. | -| Skill `/go-lint-setup` (user-invoked) | shipped | Slash-command skill — scaffold, adopt, or debug the golangci-lint v2 config in a repo. | +| Skill `/go-lint-setup` (user-invoked) | shipped | Slash-command skill: scaffolds, adopts, or debugs the golangci-lint v2 config in a repo. | | Lint config `references/golangci.v2.yml` | shipped | Reference golangci-lint v2 config (`modernize` + stack linters). | | 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 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`). +Guidance is grounded in [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*), 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 @@ -44,13 +74,13 @@ and reviewers must say so in every brief: on every touched package before committing." - **Reviewer brief:** "Before reading the diff, load `go-coding:go-coding` plus `go-errors`, `go-testing` and the skills the diff calls for; cite the rule a finding rests on. Do not dispatch - `go-reviewer` — you are the review seat." + `go-reviewer`: you are the review seat." Use `go-reviewer` directly when no such seat exists (an ad-hoc "review this file" request). ## Development -No build step — the plugin is pure Markdown + JSON. Validate locally: +The plugin has no build step. Validate locally: ```bash ./scripts/validate.sh # manifests, parity, paths, frontmatter, hooks, doc inventories, linters, fixers @@ -58,16 +88,16 @@ No build step — the plugin is pure Markdown + JSON. Validate locally: claude plugin validate . # manifest + component structure ``` -Beyond the shared structural checks, the validator enforces two invariants specific to this plugin: **advice equals tooling** — every linter a component teaches must be reachable from the reference config — and, when a Go toolchain at the floor minor is on `PATH`, the `go-idioms` **Fixer** column is verified against `go tool fix help`, so a renamed or retired fixer fails the build rather than shipping as advice. +Beyond the shared structural checks, the validator enforces two invariants specific to this plugin. The first is **advice equals tooling**: every linter a component teaches must be reachable from the reference config. The second applies when a Go toolchain at the floor minor is on `PATH`: the `go-idioms` **Fixer** column is verified against `go tool fix help`, so a renamed or retired fixer fails the build rather than shipping as advice. ## Documentation -- [docs/install.md](docs/install.md) — install on both hosts, and the Go toolchain each hook expects -- [docs/testing.md](docs/testing.md) — validate and dogfood -- [docs/versioning.md](docs/versioning.md) — SemVer policy and release steps -- [docs/authoring.md](docs/authoring.md) — skill / command / agent / rule authoring conventions +- [docs/install.md](docs/install.md): install on both hosts, and the Go toolchain each hook expects +- [docs/testing.md](docs/testing.md): validate and dogfood +- [docs/versioning.md](docs/versioning.md): SemVer policy and release steps +- [docs/authoring.md](docs/authoring.md): skill, command, agent, and rule authoring conventions -See [`AGENTS.md`](AGENTS.md) for contributor conventions. +See [AGENTS.md](AGENTS.md) for contributor conventions. ## License diff --git a/docs/authoring.md b/docs/authoring.md index ab8772f..c12c7a5 100644 --- a/docs/authoring.md +++ b/docs/authoring.md @@ -1,40 +1,42 @@ # Skill, command, agent, and rule authoring conventions -The detailed companion to [AGENTS.md](../AGENTS.md) (which is authoritative); this expands on the -*how*. The shipped components are the reference examples. +This page is for contributors adding or changing a skill, command, agent, or Cursor rule, and for +anyone refreshing the skills against current Go practice. It expands on the *how* behind +[AGENTS.md](../AGENTS.md), which stays authoritative, and it holds the source registry a refresh +re-reads. The shipped components are the reference examples. -## Naming & layout +## Naming and layout - **Components are kebab-case** and namespaced `:` (for example - `go-coding:go-errors`) — don't repeat the plugin's words in a component name. A component's + `go-coding:go-errors`); don't repeat the plugin's words in a component name. A component's frontmatter `name` MUST equal its directory (skills) or filename stem (agents); `scripts/validate.py` enforces this. - `skills//SKILL.md` (includes user-invoked slash commands) · `agents/.md` · `rules/.mdc`. Shared reference material (for example `references/golangci.v2.yml`) lives in top-level `references/`. The legacy `commands/.md` layout is not used. -## Skill vs agent vs rule +## Skill, agent, or rule -- **Skill (auto-invoked)** — a load-on-use procedure or router. Only its `description` is always-on, +- **Skill (auto-invoked)**: a load-on-use procedure or router. Only its `description` is always-on, so keep that lean (the instruction budget is finite). The `go-coding` router + the `go-*` standards skills are the model. -- **Skill (user-invoked / slash command)** — a thin one-shot `skills//SKILL.md` that also +- **Skill (user-invoked / slash command)**: a thin one-shot `skills//SKILL.md` that also carries `argument-hint` + `allowed-tools`; use `$ARGUMENTS` in the body. Invoked as `/`. See `/go-lint-setup`. (The legacy `commands/` folder is not used.) -- **Agent** — a context-isolated specialist. Use **`tools:`** (a YAML block list), **never** - `allowed-tools:` — in an agent that key is silently ignored and the agent inherits *all* tools. +- **Agent**: a context-isolated specialist. Use **`tools:`** (a YAML block list), **never** + `allowed-tools:`, because in an agent that key is silently ignored and the agent inherits *all* tools. See `go-reviewer` (report-only, no sub-agent dispatch). -- **Cursor rule** — a Cursor-only `.mdc` with `description` / `globs` / `alwaysApply` that mirrors a +- **Cursor rule**: a Cursor-only `.mdc` with `description` / `globs` / `alwaysApply` that mirrors a skill for the Cursor host. See `rules/go-context.mdc`. ## The `description` (the trigger) -For skills the `description` is always-on metadata: keep it lean (~50–75 words), third person — +For skills the `description` is always-on metadata: keep it lean (~50–75 words) and in the third person: *what + scope*, 3–5 representative triggers ("This skill should be used when…"), and a short "Not for …" anti-trigger. For commands it's the one-line palette entry; pair it with `argument-hint`. -**YAML gotcha:** a `description` value with an unquoted `: ` (colon-space) — for example writing -`version: "2"` inline — makes a real YAML parser read it as a nested mapping, so the component loads +**YAML gotcha:** a `description` value with an unquoted `: ` (colon-space), for example writing +`version: "2"` inline, makes a real YAML parser read it as a nested mapping, so the component loads with *empty* metadata (every field silently dropped). `claude plugin validate` catches this, and `scripts/validate.py` guards against it too. Reword or quote the value. @@ -43,64 +45,64 @@ with *empty* metadata (every field silently dropped). `claude plugin validate` c - **Deterministic beats prose.** Point at the tool that enforces a rule (`gofmt`/`gofumpt`, `go vet`, a `golangci-lint` linter, `modernize`, `go test -race`) rather than re-deriving it. Ground every judgment rule in a cited source (Effective Go, Go Code Review Comments, the Google or - Uber style guide, a `go.dev/blog` post, `pkg.go.dev`) — do not invent rules. + Uber style guide, a `go.dev/blog` post, `pkg.go.dev`); do not invent rules. - Imperative voice; explain *why* a rule matters rather than relying on bare MUST/NEVER. Keep skill - bodies focused — the always-on cost is the `description`; the body loads on use. + bodies focused: the always-on cost is the `description`, and the body loads on use. ## Refreshing the standards baseline (source registry) When asked to *refresh the skills against current Go practice*, re-read these sources in this order -and update the affected skill bodies — do not refresh from memory, and do not add a rule without a +and update the affected skill bodies. Do not refresh from memory, and do not add a rule without a citation. Everything the skills assert should be traceable to one of these. -**Tier 1 — normative, always check first** +**Tier 1: normative, always check first** | Source | URL | What it settles | |---|---|---| | Release notes for the baseline version | `https://go.dev/doc/go1.NN` | new APIs/idioms, experiments, removals | -| Release history | | what is actually *released* vs. draft — the baseline claim in AGENTS.md depends on this | +| Release history | | what is actually *released* versus draft; the baseline claim in AGENTS.md depends on this | | Package docs | `https://pkg.go.dev/` | exact signatures + the "added in go1.NN" annotation for every version gate | | Effective Go | | foundational idiom | | Go Code Review Comments | | the review-rule catalogue (naming, errors, concurrency, API shape) | | Doc comment syntax | | `gofmt`-formatted doc comments, doc links | -**Tier 2 — style guides (attribute when a rule comes from one, and name the document)** +**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 +- Google Go Style Guide: three documents of different weight, ranked by Google itself; a citation names which one: - - the *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* — — **normative, not canonical**: the reviewer rulebook — naming, + - the *Guide* (), **normative and canonical**: the five ordered readability principles + (clarity, simplicity, concision, maintainability, consistency) and, under simplicity, *least mechanism*. This is + the tie-break order the router, the Cursor rule and the reviewer use, as one identical sentence in + all three, checked by `scripts/validate.py`. + - *Style Decisions* (), **normative, not canonical**: the reviewer rulebook for naming, commentary, imports, errors, language, common libraries, useful test failures. The main Google source for skill rules. - - *Best Practices* — — **advisory**: patterns with trade-offs (test doubles, option structs, + - *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 — +- Uber Go Style Guide: -**Tier 3 — the enforcing tools (this is what keeps "advice == tooling" true)** +**Tier 3: the enforcing tools (this is what keeps "advice == tooling" true)** -- **`go tool fix help` on the floor-version toolchain** — the authority for which fixers `go fix` - actually ships (the plain rows in the `go-idioms` **Fixer** column); `go fix` blog — +- **`go tool fix help` on the floor-version toolchain**: the authority for which fixers `go fix` + actually ships (the plain rows in the `go-idioms` **Fixer** column). The `go fix` blog post: -- `modernize` per-fixer docs — - — tracks x/tools **tip**, usually ahead of the toolchain: the source for **†** rows, never - evidence that a fixer ships in `go fix` -- golangci-lint docs — · v1→v2 migration — - · changelog (for the CI pin) — +- `modernize` per-fixer docs: . + These track x/tools **tip**, which is usually ahead of the toolchain, so they are the source for **†** rows and + never evidence that a fixer ships in `go fix` +- golangci-lint docs: · v1→v2 migration: + · changelog (for the CI pin): - `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 +- **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 ; staticcheck checks ; revive rules ; errorlint ; gofumpt rules ; the golangci-lint linters index -**Revision record** — the mutable sources, as last read. A refresh diffs each against its recorded +**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 | @@ -109,42 +111,42 @@ revision first, so it reads what changed rather than everything, then updates th | 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 | +| Effective Go, doc comment syntax, `cmd/vet`, package docs | versioned with the Go release; read at go1.27.1 | 2026-09-09 | **Procedure** -1. Confirm the current *released* Go version (release history) — a draft `go1.NN` page is not a +1. Confirm the current *released* Go version (release history); a draft `go1.NN` page is not a baseline. Guidance for an unreleased version goes in as one *italic, explicitly labelled* sentence (`*Go 1.NN (draft, expected …)*`), never as a rule. **The baseline is a hard floor** (currently **Go 1.26.4+**; Go 1.27 is supported too, with its additions flagged as hints rather than folded into the floor): recommend the modern form flat, with no "on 1.NN+ modules prefer…" hedging and no fallback branch for older toolchains. Keep the - version annotation (`Since`, "(Go 1.24)") — that is provenance, and it tells a reader on an older + version annotation (`Since`, "(Go 1.24)"): that is provenance, and it tells a reader on an older module what a bump would buy. When the floor moves, delete the guidance below it. -2. Diff each `go-*` skill against Tier 1 for the baseline and the two prior versions — the common +2. Diff each `go-*` skill against Tier 1 for the baseline and the two prior versions. The common miss is a stdlib API that landed *after* a skill was written (`errors.AsType`, `t.ArtifactDir`). 3. Verify every version gate in `pkg.go.dev`'s "added in" annotation before writing a `Since` cell. -4. Re-check the Tier 3 tool names — a renamed or dropped fixer/linter turns a rule into a wrong +4. Re-check the Tier 3 tool names: a renamed or dropped fixer/linter turns a rule into a wrong command (`waitgroup` → `waitgroupgo`). **Run the tool, don't read about it:** when a floor-version toolchain is available, - `go tool fix help` settles fixer names in one command — pkg.go.dev's modernize page tracks + `go tool fix help` settles fixer names in one command, whereas pkg.go.dev's modernize page tracks x/tools tip, which is usually ahead of what `go fix` ships; same idea for linters (`golangci-lint help linters` on the pinned build). `scripts/validate.py` enforces both 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 + 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. An analyzer a skill - teaches as *opt-in* — `shadow` in `go-idioms` — is the deliberate exception to the first half: it + 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. + 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. Run `python3 scripts/validate.py --check-links` — every cited URL must still resolve; a moved +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]`. @@ -160,6 +162,6 @@ and the Cursor hook command **workspace-relative** (`bash hooks/session-start.sh ## Before committing -Run `./scripts/validate.sh` and `claude plugin validate .`, then test triggering locally — see +Run `./scripts/validate.sh` and `claude plugin validate .`, then test triggering locally; see [testing.md](testing.md). When adding or renaming a component, sync **AGENTS.md**, **README.md**, and **CHANGELOG.md** in lockstep. diff --git a/docs/install.md b/docs/install.md index 8a4fb57..c3625e3 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,14 +1,12 @@ # Installing the Go Coding Plugin -> This plugin is pure Markdown + JSON — there is no build step and **no MCP server** to wire up. - -This plugin is distributed for both [Claude Code](https://docs.claude.com/en/docs/claude-code/plugins) (`.claude-plugin/`) and [Cursor](https://cursor.com/docs/plugins) (`.cursor-plugin/`). Skill, agent, and rule content is shared; only the manifest and hook layer differ. +This page is for anyone installing, updating, or dogfooding the plugin: the Claude Code marketplace install, a local working copy for development, Cursor, and the Go toolchain the hooks expect on the host. The plugin is distributed for both [Claude Code](https://docs.claude.com/en/docs/claude-code/plugins) (`.claude-plugin/`) and [Cursor](https://cursor.com/docs/plugins) (`.cursor-plugin/`). Skill, agent, and rule content is shared; only the manifest and hook layer differ. The plugin is pure Markdown + JSON, so there is no build step and **no MCP server** to wire up. ## Claude Code ### Install (from the Cadasto marketplace) -``` +```text /plugin marketplace add Cadasto/plugin-marketplace /plugin install go-coding@cadasto ``` @@ -21,9 +19,9 @@ The marketplace name is `cadasto`, so the plugin is addressed as `go-coding@cada claude --plugin-dir /path/to/go-coding-plugin ``` -`--plugin-dir` loads the plugin from disk for **that session only** — it does not persist, which makes it the right tool for dogfooding an unreleased working copy. It is repeatable (`--plugin-dir A --plugin-dir B`) and also accepts a `.zip`. +`--plugin-dir` loads the plugin from disk for **that session only**. It does not persist, which makes it the right tool for dogfooding an unreleased working copy. It is repeatable (`--plugin-dir A --plugin-dir B`) and also accepts a `.zip`. -Claude Code has **no `plugin add` subcommand**. `claude plugin install` resolves names from a configured marketplace, not filesystem paths, and `claude plugin marketplace add ` expects a marketplace manifest (`.claude-plugin/marketplace.json`) — which a single-plugin repository like this one does not have. For a persistent install, go through the marketplace above. +Claude Code has **no `plugin add` subcommand**. `claude plugin install` resolves names from a configured marketplace, not filesystem paths, and `claude plugin marketplace add ` expects a marketplace manifest (`.claude-plugin/marketplace.json`), which a single-plugin repository like this one does not have. For a persistent install, go through the marketplace above. ### Inspect / update @@ -32,7 +30,7 @@ claude plugin validate . # manifest + component structure claude plugin details go-coding # component inventory + projected token cost ``` -``` +```text /plugin marketplace update cadasto /plugin update go-coding ``` @@ -45,21 +43,21 @@ Add this repository as a plugin (Cursor **Settings → Plugins**, via Git URL or ## Host toolchain (minimal requirements) -Installing the plugin itself needs no Go toolchain — it is pure Markdown + JSON. But its **enforcement** layer only delivers value when the standard Go tools are on the host `PATH`: the `format-on-save` hook shells out to a formatter, the golangci-lint v2 reference config lists `gofumpt`/`goimports` as formatters, and the recommended official `gopls-lsp` plugin (`@claude-plugins-official`) drives `gopls`. The plugin targets **Go 1.26.4+** + golangci-lint v2 as a hard floor — it does not carry fallback guidance for 1.25 or older modules. +Installing the plugin itself needs no Go toolchain, because the plugin is pure Markdown + JSON. Its **enforcement** layer only delivers value when the standard Go tools are on the host `PATH`: the `format-on-save` hook shells out to a formatter, the golangci-lint v2 reference config lists `gofumpt`/`goimports` as formatters, and the recommended official `gopls-lsp` plugin (`@claude-plugins-official`) drives `gopls`. The plugin targets **Go 1.26.4+** + golangci-lint v2 as a hard floor: it carries no fallback guidance for 1.25 or older modules. At minimum the host should provide: | Tool | Provided by | Used for | If missing | |------|-------------|----------|------------| | **Go 1.26.4+ (1.27.x recommended)** | [go.dev/dl](https://go.dev/dl/) / package manager | everything; satisfies a `go.mod` `go 1.26.x` or `1.27.x` directive; `go fix ./...` runs the modernizers | no toolchain at all | -| **`gofmt`** | the Go distribution | `format-on-save.sh` fallback (`gofmt -w -s`) | n/a — always ships with Go | +| **`gofmt`** | the Go distribution | `format-on-save.sh` fallback (`gofmt -w -s`) | n/a: always ships with Go | | **`gofumpt`** | `go install` | `format-on-save.sh` primary (`gofumpt -w`), stricter gofmt superset | hook degrades to `gofmt` | | **`goimports`** | `go install` | `goimports` formatter in the golangci-lint v2 config (import grouping/pruning) | import-group formatting skipped | | **`gopls`** (v0.23.x) | `go install` | the `gopls-lsp` plugin (defs/refs/diagnostics/rename/vulncheck) | no code intelligence | ### Install / upgrade Go (official tarball, Linux) -Pick the latest **1.27.x** patch (**go1.27.1** at time of writing) from and the build matching your platform (`linux-amd64` shown) — the plugin's floor is **Go 1.26.4 or newer**, so an existing 1.26.4+ toolchain also works and nothing below requires the upgrade: +Pick the latest **1.27.x** patch (**go1.27.1** at time of writing) from and the build matching your platform (`linux-amd64` shown). The plugin's floor is **Go 1.26.4 or newer**, so an existing 1.26.4+ toolchain also works and nothing below requires the upgrade: ```bash # replace the version with the current latest 1.27.x patch (go1.27.1 at time of writing; 1.26.4+ also works) @@ -70,11 +68,11 @@ export PATH=$PATH:/usr/local/go/bin # add to your shell p go version # → go version go1.27.1 linux/amd64 ``` -> macOS/Windows or a package manager (Homebrew `go`, `winget`, distro packages) work equally well — the only requirement is that `go version` reports **1.26.4 or newer** (1.27.x recommended). `gofmt` is included in every Go distribution, so nothing extra is needed for the hook's fallback path. +> macOS/Windows or a package manager (Homebrew `go`, `winget`, distro packages) work equally well. The only requirement is that `go version` reports **1.26.4 or newer** (1.27.x recommended). `gofmt` is included in every Go distribution, so nothing extra is needed for the hook's fallback path. ### Install the supporting tools -`go install` drops binaries in `$(go env GOPATH)/bin` (default `~/go/bin`) — make sure that directory is on your `PATH`. Run these **after** Go is in place so they compile against your installed toolchain (1.26.4+ or 1.27.x): +`go install` drops binaries in `$(go env GOPATH)/bin` (default `~/go/bin`); make sure that directory is on your `PATH`. Run these **after** Go is in place so they compile against your installed toolchain (1.26.4+ or 1.27.x): ```bash go install mvdan.cc/gofumpt@latest # stricter gofmt superset (hook primary) @@ -92,14 +90,14 @@ command -v goimports # goimports has no --version flag gopls version # → golang.org/x/tools/gopls v0.23.x ``` -These are **host-only** dev tools; the plugin still works without them (the format hook degrades to `gofmt`, then to a silent no-op). Full-tree `golangci-lint` runs separately — often in a pinned container — so it does not depend on these host binaries. On Go 1.27, that container/pin needs **golangci-lint ≥ v2.13.0** (released 2026-08-19, the release that added Go 1.27 support) — see ; anything older predates 1.27 support. +These are **host-only** dev tools; the plugin still works without them (the format hook degrades to `gofmt`, then to a silent no-op). Full-tree `golangci-lint` runs separately (often in a pinned container), so it does not depend on these host binaries. On Go 1.27, that container/pin needs **golangci-lint ≥ v2.13.0** (released 2026-08-19, the release that added Go 1.27 support); see the [golangci-lint v2.13.0 changelog](https://golangci-lint.run/docs/product/changelog/#2130). Anything older predates 1.27 support. ## Hooks The plugin ships three host-agnostic hooks (Claude `hooks/hooks.json`, Cursor `hooks/cursor-hooks.json`): -- **`session-start.sh`** — on session start, detects a Go workspace (`go.mod`/`*.go`) and prints one standards line. -- **`format-on-save.sh`** — after each edit of a `*.go` file (Claude `PostToolUse` on `Write`/`Edit`; Cursor `afterFileEdit`), runs **`gofumpt -w`** on that file, or **`gofmt -w -s`** when `gofumpt` is not installed. It is **host-only** (no container round-trip), **edits the file in place**, and is a **silent no-op** when no Go formatter is on `PATH` — so install `gofmt` (ships with Go) or `gofumpt` to benefit. It never blocks an edit. This is per-file formatting only; run `golangci-lint` and your tests via CI/`make` for full-tree checks. -- **`skill-nudge.sh`** — after each edit of a `*.go` file (same trigger as `format-on-save.sh`), names ONE matching go-coding skill for that edit (a `_test.go` file → `go-testing`; goroutine/channel/`sync`/`atomic`/`errgroup` content → `go-concurrency`; `fmt.Errorf`/`errors.*` → `go-errors`), once per skill per session. Delivered as a hook `systemMessage` under Claude Code (reaches the model's context on exit 0) or a plain line under Cursor. It never blocks an edit. +- **`session-start.sh`**: on session start, detects a Go workspace (`go.mod`/`*.go`) and prints one standards line. +- **`format-on-save.sh`**: after each edit of a `*.go` file (Claude `PostToolUse` on `Write`/`Edit`; Cursor `afterFileEdit`), runs **`gofumpt -w`** on that file, or **`gofmt -w -s`** when `gofumpt` is not installed. It is **host-only** (no container round-trip), **edits the file in place**, and is a **silent no-op** when no Go formatter is on `PATH`, so install `gofmt` (ships with Go) or `gofumpt` to benefit. It never blocks an edit. This is per-file formatting only; run `golangci-lint` and your tests via CI/`make` for full-tree checks. +- **`skill-nudge.sh`**: after each edit of a `*.go` file (same trigger as `format-on-save.sh`), names ONE matching go-coding skill for that edit (a `_test.go` file → `go-testing`; goroutine/channel/`sync`/`atomic`/`errgroup` content → `go-concurrency`; `fmt.Errorf`/`errors.*` → `go-errors`), once per skill per session. Delivered as a hook `systemMessage` under Claude Code (reaches the model's context on exit 0) or a plain line under Cursor. It never blocks an edit. > The Cursor wiring targets the `afterFileEdit` event; if your Cursor version exposes a different post-edit event or payload shape, adjust `hooks/cursor-hooks.json` and the path-extraction in `format-on-save.sh` accordingly. diff --git a/docs/testing.md b/docs/testing.md index 1260f35..b540793 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -1,42 +1,44 @@ # Testing and validation -This is a pure-content repository — JSON manifests + Markdown components, with no build -step or package manager. Testing means validating structure, then installing locally and -exercising the components. +This page is for contributors checking a change before a pull request or a release: what each +validator checks, how to exercise the components by hand, and how to measure skill adoption. +The repository is pure content (JSON manifests and Markdown components) with no build step or +package manager, so testing means validating structure, then installing locally and exercising +the components. ## Validation -- **Manifest / component validation** — `./scripts/validate.sh`: checks both `plugin.json` manifests, dual-host parity (name/version/description/author agree), declared component paths, kebab-case names, hook-config JSON, hook parity (the same `hooks/*.sh` wired for the equivalent event on both hosts, each existing and executable, none left unwired), doc component inventories (every shipped skill, agent and hook named where the docs claim to list them), and SKILL.md / agent / command frontmatter (including `name` == directory/filename, and that agents declare `tools:` not `allowed-tools:`). The wrapper runs `scripts/validate.py`; if Python 3 isn't installed it prints a warning and skips (exit 0) rather than failing — install `python3` for the full local check, or rely on `claude plugin validate .` and CI. CI pins Python and calls `python3 scripts/validate.py` directly, so the deep check can never silently skip there. -- **Validator self-test** — `python3 scripts/validate.py --selftest` (also run by CI): rebuilds each structural check's failure case in a temporary tree and requires the check to catch it, so a check that has quietly stopped checking cannot pass as green. It also exercises the link checker's fetch policy — HEAD then GET, one retry on a transport error or an HTTP 429/503, a 404 reported as broken — against a local HTTP server, with no network access. -- **Link check** — `python3 scripts/validate.py --check-links`: every URL cited in skills, agents, rules, and docs must resolve. Needs the network, so it is its own switch; CI runs it weekly and on pull requests that touch those files, the checker itself, or its workflow (`.github/workflows/links.yml`). -- **Hook tests** — `./scripts/hooks-test.sh` (also run by CI on every PR): bash tests for all three hook scripts (`hooks/session-start.sh`, `hooks/format-on-save.sh`, `hooks/skill-nudge.sh`), including a can-fail self-test block that proves the negative-case helpers actually fail on bad input. -- **Official validator** — `claude plugin validate .`: checks the manifest and component structure (no extra dependencies). -- **Structural review** — run the `plugin-dev:plugin-validator` agent after creating or modifying components. -- **Skill quality review** — run the `plugin-dev:skill-reviewer` agent: description-triggering quality, progressive disclosure, content structure. -- **Token cost** — `claude plugin details go-coding` shows the inventory and projected token cost; keep skill/command metadata lean. +- **Manifest / component validation**: `./scripts/validate.sh` checks both `plugin.json` manifests, dual-host parity (name/version/description/author agree), declared component paths, kebab-case names, hook-config JSON, hook parity (the same `hooks/*.sh` wired for the equivalent event on both hosts, each existing and executable, none left unwired), doc component inventories (every shipped skill, agent and hook named where the docs claim to list them), and SKILL.md / agent / command frontmatter (including `name` == directory/filename, and that agents declare `tools:` not `allowed-tools:`). The wrapper runs `scripts/validate.py`; if Python 3 isn't installed it prints a warning and skips (exit 0) rather than failing. Install `python3` for the full local check, or rely on `claude plugin validate .` and CI. CI pins Python and calls `python3 scripts/validate.py` directly, so the deep check can never silently skip there. +- **Validator self-test**: `python3 scripts/validate.py --selftest` (also run by CI) rebuilds each structural check's failure case in a temporary tree and requires the check to catch it, so a check that has quietly stopped checking cannot pass as green. It also exercises the link checker's fetch policy (HEAD then GET, one retry on a transport error or an HTTP 429/503, a 404 reported as broken) against a local HTTP server, with no network access. +- **Link check**: with `python3 scripts/validate.py --check-links`, every URL cited in skills, agents, rules, and docs must resolve. Needs the network, so it is its own switch; CI runs it weekly and on pull requests that touch those files, the checker itself, or its workflow (`.github/workflows/links.yml`). +- **Hook tests**: `./scripts/hooks-test.sh` (also run by CI on every PR) runs bash tests for all three hook scripts (`hooks/session-start.sh`, `hooks/format-on-save.sh`, `hooks/skill-nudge.sh`), including a can-fail self-test block that proves the negative-case helpers actually fail on bad input. +- **Official validator**: `claude plugin validate .` checks the manifest and component structure (no extra dependencies). +- **Structural review**: run the `plugin-dev:plugin-validator` agent after creating or modifying components. +- **Skill quality review**: run the `plugin-dev:skill-reviewer` agent for description-triggering quality, progressive disclosure, content structure. +- **Token cost**: `claude plugin details go-coding` shows the inventory and projected token cost; keep skill/command metadata lean. ## Local triggering tests Install from your working copy (see [install.md](install.md)), then exercise each component: -- **Session-start hook** — open a repo with a `go.mod`/`*.go`; one Go-standards line should print at session start (and nothing in a non-Go repo). -- **`go-coding` router** — ask for a Go review or idiom help; it should route to the enforcing tool and the focused skill. -- **Standards skills** — a topic prompt should engage the matching skill (for example error wrapping → `go-errors`, a flaky time-based test → `go-testing`/`go-concurrency`, linter setup → `go-lint-setup`). -- **Format-on-save hook** — save a deliberately mis-formatted `*.go` file; `format-on-save.sh` should reformat that one file in place (`gofumpt -w`, or `gofmt -w -s` when `gofumpt` is absent) and say nothing when neither is installed. -- **Skill-nudge hook** — edit a `_test.go` file; the nudge should name `go-coding:go-testing` (as a systemMessage under Claude Code, a plain line under Cursor) and, critically, the model should ACT on it — load the skill — not merely have the line appear in the transcript. A second edit to a `_test.go` file in the same session should be silent (once per skill per session), and so should an edit that does not itself touch the topic — a doc-comment fix in a file that defines a sentinel elsewhere must not claim the edit touches an error path. -- **`go-reviewer` agent** — ask for a Go code review; it returns severity-ranked findings and does not spawn sub-agents. -- **Slash command (skill)** — `/go-lint-setup`. -- **Cursor rule** — in Cursor, open a `.go` file and confirm `go-context.mdc` attaches. +- **Session-start hook**: open a repo with a `go.mod`/`*.go`; one Go-standards line should print at session start (and nothing in a non-Go repo). +- **`go-coding` router**: ask for a Go review or idiom help; it should route to the enforcing tool and the focused skill. +- **Standards skills**: a topic prompt should engage the matching skill (for example error wrapping → `go-errors`, a flaky time-based test → `go-testing`/`go-concurrency`, linter setup → `go-lint-setup`). +- **Format-on-save hook**: save a deliberately mis-formatted `*.go` file; `format-on-save.sh` should reformat that one file in place (`gofumpt -w`, or `gofmt -w -s` when `gofumpt` is absent) and say nothing when neither is installed. +- **Skill-nudge hook**: edit a `_test.go` file; the nudge should name `go-coding:go-testing` (as a systemMessage under Claude Code, a plain line under Cursor) and, critically, the model should ACT on it (load the skill), not merely have the line appear in the transcript. A second edit to a `_test.go` file in the same session should be silent (once per skill per session), and so should an edit that does not itself touch the topic: a doc-comment fix in a file that defines a sentinel elsewhere must not claim the edit touches an error path. +- **`go-reviewer` agent**: ask for a Go code review; it returns severity-ranked findings and does not spawn sub-agents. +- **Slash command (skill)**: `/go-lint-setup`. +- **Cursor rule**: in Cursor, open a `.go` file and confirm `go-context.mdc` attaches. After editing content, reinstall (or restart the session) to pick up changes. ## Measuring adoption -The layout and concurrency skills, and the router's dispatch behavior, were shaped by +The layout and concurrency skills, and the router's dispatch behaviour, were shaped by a usage analysis of local Claude Code session transcripts. `scripts/usage-report.py` (stdlib-only) reproduces that measurement so adoption stays checkable over time: -``` +```bash python3 scripts/usage-report.py --since YYYY-MM-DD --out report.md ``` @@ -49,13 +51,13 @@ file instead. `--help` repeats the counting rules. `` invocation naming a go-coding skill. Events are split into main-session, subagent, and user-invoked, per month. The report renders two tables: "Per skill / agent" counts every event (so a skill loaded three times in one session counts three times), and -"Sessions with >=1 event, per skill / agent" counts distinct sessions instead — a skill +"Sessions with >=1 event, per skill / agent" counts distinct sessions instead, so a skill loaded three times in one session counts once there. The 50% target below is read off the sessions table: (sessions loading a given focused skill) / (sessions loading `go-coding:go-coding`). **Not counted:** the SessionStart banner line, or skill-body text echoed back inside -tool results — only structured tool invocations and explicit slash-command text count. +tool results: only structured tool invocations and explicit slash-command text count. Nor is Cursor: the script reads Claude Code transcripts (`~/.claude/projects`) only, so the numbers describe adoption on one of the two hosts. diff --git a/docs/versioning.md b/docs/versioning.md index 1d5d524..8c5d311 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -1,13 +1,14 @@ # Versioning and releases -This plugin uses [Semantic Versioning](https://semver.org), adapted to skill / command / agent / -rule content: +This page is for maintainers cutting a release: how to choose the version bump, the release +steps, and how a release reaches users through the Cadasto marketplace. The plugin uses +[Semantic Versioning](https://semver.org), adapted to skill, command, agent, and rule content: | Bump | When | |------|------| | **Major** | A skill/command/agent/rule is removed or renamed, or its behaviour/scope changes incompatibly | | **Minor** | A new component is added, or an existing one's coverage meaningfully expands | -| **Patch** | Typos, clarifications, reference/source fixes — no behaviour change | +| **Patch** | Typos, clarifications, reference/source fixes; no behaviour change | While on the `0.x` line, treat the plugin as pre-stable: a breaking change may still ship in a minor bump. @@ -15,19 +16,20 @@ bump. ## Release steps 1. Bump `version` in **both** manifests (they must agree): `.claude-plugin/plugin.json` and - `.cursor-plugin/plugin.json`. Keep `description` and `author` identical across both — + `.cursor-plugin/plugin.json`. Keep `description` and `author` identical across both; `scripts/validate.py` enforces this parity. 2. Run `./scripts/validate.sh`, `./scripts/hooks-test.sh`, and `claude plugin validate .`. 3. **Dogfood:** load the working copy (`claude --plugin-dir /path/to/go-coding-plugin`) and - exercise the components against a real Go change on **both** hosts — see [testing.md](testing.md). + exercise the components against a real Go change on **both** hosts; see [testing.md](testing.md). 4. Fold the accumulated `## [Unreleased]` notes into a dated `## [X.Y.Z] - YYYY-MM-DD` section in - [CHANGELOG.md](../CHANGELOG.md) (Keep a Changelog — groups in order Added, Changed, Deprecated, + [CHANGELOG.md](../CHANGELOG.md) (Keep a Changelog: groups in order Added, Changed, Deprecated, Removed, Fixed, Security; see [AGENTS.md](../AGENTS.md#changelog-style)). -5. Sync the docs surface (AGENTS.md, README.md) with what shipped. If the session-start hook's - output ever lists components, keep that in step too. -6. Commit (`chore(release): vX.Y.Z`) and tag: `git tag -a vX.Y.Z -m "go-coding-plugin vX.Y.Z"`. -7. Push commits and the tag: `git push origin main --follow-tags`. -8. **Update the marketplace entry** — the release is not live until this lands. See below. +5. Sync the docs surface (AGENTS.md, README.md) with what shipped, and the component list in the + session-start hook's banner (`hooks/session-start.sh`). +6. Update the version badge in [README.md](../README.md) to `X.Y.Z`. +7. Commit (`chore(release): vX.Y.Z`) and tag: `git tag -a vX.Y.Z -m "go-coding-plugin vX.Y.Z"`. +8. Push commits and the tag: `git push origin main --follow-tags`. +9. **Update the marketplace entry**: the release is not live until this lands. See below. ## No MCP coupling @@ -37,13 +39,13 @@ This plugin has **no companion MCP server**, so there is no server-compatibility This plugin is listed in the [Cadasto marketplace](https://github.com/Cadasto/plugin-marketplace) as `go-coding@cadasto`. The catalog **pins every entry to a release tag**, so tagging and pushing a -release here does not ship it — users see nothing until the marketplace entry moves. +release here does not ship it: users see nothing until the marketplace entry moves. -After step 7, update the entry in `Cadasto/plugin-marketplace`: +After step 8, update the entry in `Cadasto/plugin-marketplace`: 1. Bump that entry's `version` to `X.Y.Z` and `source.ref` to `vX.Y.Z` together (validation there rejects a mismatch). -2. Bump the catalog's own `metadata.version` — a plugin minor/major is a catalog **minor**, a plugin +2. Bump the catalog's own `metadata.version`: a plugin minor/major is a catalog **minor**, a plugin patch is a catalog **patch**. 3. Add a dated `## [X.Y.Z] - YYYY-MM-DD` section in the catalog `CHANGELOG.md`, then run `python3 scripts/validate.py --fix`. @@ -51,4 +53,4 @@ After step 7, update the entry in `Cadasto/plugin-marketplace`: See the catalog's [docs/versioning.md](https://github.com/Cadasto/plugin-marketplace/blob/main/docs/versioning.md). The catalog copies `description`, `version`, and `keywords` verbatim from `.claude-plugin/plugin.json`, -so update the entry whenever any of those change — not only on a release. +so update the entry whenever any of those change, not only on a release.