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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,19 @@
}
}
},
{
"name": "go-format",
"source": "./plugins/go-format",
"category": "development",
"tags": ["go", "golang", "goimports", "formatter", "hook"],
"relevance": {
"topic": "Go",
"signals": {
"filesRead": ["**/*.go"],
"cli": ["goimports"]
}
}
},
{
"name": "eol-normalizer",
"displayName": "EOL Normalizer",
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,13 @@ user opts in with `/plugin enable`; an existing install is never flipped by cata
- [`biome-format`](plugins/biome-format) — Auto-format and lint JS/TS/JSX/JSON on edit via Biome, only when a biome.json governs the repo — using the consuming repo's own Biome config.
- [`ruff-format`](plugins/ruff-format) — Auto-format and lint Python on edit via Ruff, only when a Ruff config governs the repo — using the consuming repo's own Ruff config.
- [`typos-format`](plugins/typos-format) — Auto-fix spelling typos on edit via typos-cli, unconditionally — honoring the consuming repo's own typos configuration when one is present.
- [`go-format`](plugins/go-format) — Auto-fix Go formatting and import management on edit via goimports — runs unconditionally (no consumer-config gate), skipping generated files.
- [`eol-normalizer`](plugins/eol-normalizer) — Normalize a written file's working-tree line endings to its .gitattributes eol value on edit — symmetric CRLF/LF driven by git check-attr, advisory and never blocking.
- [`powershell-format`](plugins/powershell-format) — Auto-format and lint PowerShell on edit via PSScriptAnalyzer, only when a PSScriptAnalyzerSettings.psd1 governs the repo — using the consuming repo's own analyzer settings.
- [`actionlint`](plugins/actionlint) — Lint GitHub Actions workflow files on edit via actionlint, surfacing findings as advisory context.
- [`source-control`](plugins/source-control) — Git and GitHub delivery workflow: /commit (Conventional Commits + Co-Authored-By trailer via safe heredoc mechanics), /pull-request (prep, create, CI monitoring, review-comment triage, merge, CI-log fetch), /babysit-prs (self-pacing fleet loop — safe by default; opt-in worker/autopilot tiers add gate-checked merge and thread resolution behind a deterministic Python engine), /worktree (create, status, cleanup, audit for parallel-session isolation), /setup (check the effective commit-subject / PR-title convention merged across its config layers and the babysit-prs config, or apply — interview the repo and write the convention config to a chosen layer), and /resolve-conflicts (intent-first merge/rebase conflict resolution with a semantic-conflict sweep — never --abort). The commit-subject / PR-title convention is configurable via a source-control.md config written by a re-runnable setup skill, layered across a ~/.claude user-global file, the tracked team file, and a gitignored .claude/source-control.local.md personal overlay merged per key; Conventional Commits is the default when no convention is declared.
- [`implementation`](plugins/implementation) — Disciplined implementation stage: execute approved plans inline (`/implementation:implement`) or via orchestrated worker subagents (`/implementation:implement-dispatch`) with incremental validation, TDD-by-default cadence, green-checkpoint commits, scope-fence drift detection, and divergence detection that routes back to planning. Build/test/lint, testing, and outcome verification live in the companion `toolchain`, `testing`, and `verification` plugins, invoked when installed.
- [`toolchain`](plugins/toolchain) — Repo-agnostic polyglot verification toolchain: build + test + lint for changed files across .NET, Python, TypeScript, Bash, PowerShell, Markdown, YAML, and cross-cutting surfaces (`/toolchain:check`, `/toolchain:lint`), plus a re-runnable `/toolchain:setup` with check (report the configured ecosystems and their command surface) and apply (interview, infer, and write the tracked per-ecosystem command config those skills resolve first).
- [`toolchain`](plugins/toolchain) — Repo-agnostic polyglot verification toolchain: build + test + lint for changed files across .NET, Python, TypeScript, Bash, PowerShell, Markdown, Go, YAML, and cross-cutting surfaces (`/toolchain:check`, `/toolchain:lint`), plus a re-runnable `/toolchain:setup` with check (report the configured ecosystems and their command surface) and apply (interview, infer, and write the tracked per-ecosystem command config those skills resolve first).

### Testing

Expand Down
16 changes: 16 additions & 0 deletions docs/conventions/ecosystem-commands/examples/go.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Example .claude/ecosystems/go.yaml — a consuming repo's Go command surface.
# Contract: docs/conventions/ecosystem-commands/README.md (schema: ecosystem.schema.json).
globs: ["*.go", "go.mod", "go.sum"]
project-discovery: ["go.mod"]
build-cmd: "go build ./..."
test-cmd: "go test ./..."
check-cmd: "golangci-lint run ./..."
fix-cmd: "golangci-lint run --fix ./..."
opt-in: ".golangci.yml, .golangci.yaml, .golangci.toml, or .golangci.json present (walked from the changed file up to the repo root) — otherwise golangci-lint applies its own unconfigured \"standard\" linter preset unconditionally"
install-hint: "Install golangci-lint: https://golangci-lint.run/docs/welcome/install/ | Go toolchain: https://go.dev/dl/"
gates:
- name: go-mod-tidy-drift
cmd: "go mod tidy -diff"
trigger-globs: ["go.mod", "go.sum", "*.go"]
remediation: "Run go mod tidy and commit the updated go.mod/go.sum. (go mod tidy -diff requires Go 1.23+; on an older toolchain the gate errors on the unrecognized flag rather than reporting drift.)"
notes: "govulncheck is intentionally not a rung-4 default (per the epic brief's \"optional\" framing) — add it as a consumer-local gate via .claude/ecosystems/go.local.yaml if desired."
1 change: 1 addition & 0 deletions docs/conventions/hook-telemetry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ producers without coordinating with them or each other.
| `markdown-format` plugin | `markdown-format` | `data/markdown-format.schema.json` |
| `typos-format` plugin | `typos-format` | `data/typos-format.schema.json` |
| `ruff-format` plugin | `ruff-format` | `data/ruff-format.schema.json` |
| `go-format` plugin | `go-format` | `data/go-format.schema.json` |
| `bash-format` plugin | `bash-format` | `data/bash-format.schema.json` |
| `desktop-notification` plugin | `desktop-notification` | `data/desktop-notification.schema.json` |
| `guardrails` plugin | `secret-pattern-detection` | `data/secret-pattern-detection.schema.json` |
Expand Down
24 changes: 24 additions & 0 deletions docs/conventions/hook-telemetry/data/go-format.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/melodic-software/claude-code-plugins/main/docs/conventions/hook-telemetry/data/go-format.schema.json",
"title": "go-format telemetry data",
"description": "Per-hook `data` payload for the go-format hook. Discovered from the envelope `hook` value \"go-format\". Evolves additive-only.",
"type": "object",
"required": ["tool", "file", "findings"],
"additionalProperties": true,
"properties": {
"tool": {
"type": "string",
"description": "Claude Code tool that triggered the hook (Write or Edit)."
},
"file": {
"type": "string",
"description": "Path of the formatted Go file, relative to the consuming repo root."
},
"findings": {
"type": "array",
"items": { "type": "string" },
"description": "goimports syntax-error diagnostic lines when the file could not be parsed, one line per diagnostic. Empty array = clean or successfully autofixed (a successful format/import fix carries no findings)."
}
}
}
26 changes: 26 additions & 0 deletions plugins/go-format/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "go-format",
"version": "0.1.0",
"description": "Auto-fix Go formatting and import management on edit via goimports — runs unconditionally (no consumer-config gate), skipping generated files.",
"author": {
"name": "Melodic Software",
"email": "info@melodicsoftware.com"
},
"license": "MIT",
"keywords": [
"go",
"golang",
"goimports",
"formatter",
"hook"
],
"userConfig": {
"go_format_enabled": {
"type": "boolean",
"title": "go-format hook",
"description": "Run goimports -w on edit of a Go file",
"default": true
}
}
}
21 changes: 21 additions & 0 deletions plugins/go-format/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Changelog

All notable changes to the `go-format` plugin are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning.

## [0.1.0]

### Added

- Initial release: a `PostToolUse` hook that runs `goimports -w` on
`Write`/`Edit` of a `.go` file — unconditionally, with no consumer-config
opt-in gate (the one deliberate shape difference from the
`ruff-format`/`typos-format` pattern; see issue #832's field survey).
Skips files carrying Go's `// Code generated ... DO NOT EDIT.` marker.
Syntax errors goimports can't parse surface via `additionalContext` as an
advisory finding, never a tool break. Advisory only — never blocks the
edit.
- `hook-telemetry` conformance: emits a schema-valid envelope
(`docs/conventions/hook-telemetry/data/go-format.schema.json`) via the
shared `hook::emit_telemetry` helper.
- `/go-format:setup check|apply` skill for prerequisite verification.
101 changes: 101 additions & 0 deletions plugins/go-format/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# go-format

A Claude Code plugin that formats Go files and manages their imports the
moment you edit them. On every `Write` or `Edit` of a `.go` file it runs
[goimports](https://pkg.go.dev/golang.org/x/tools/cmd/goimports)'s `-w`,
which adds missing imports, removes unused ones, and applies `gofmt`-
equivalent formatting — then surfaces any syntax error goimports can't parse
back to Claude as advisory context.

## Behavior

- **Unconditional — no consumer-config opt-in gate.** Unlike sibling
formatter plugins (`ruff-format`, `typos-format`), this hook runs on every
edited `.go` file regardless of repository configuration. `goimports`'
own docs describe it as "a replacement for your editor's gofmt-on-save
hook" and it has no meaningful config-divergence axis when left
unconfigured — running it does not impose a style choice a repo hasn't
made, the same reasoning that makes `gofmt` itself safe to run
unconditionally.
- **Extension-scoped.** Only `.go` files trigger the hook (like
`ruff-format`'s `*.py`/`*.pyi` filter; unlike `typos-format`'s
language-agnostic scope).
- **Skips generated files.** A file whose leading comment/blank-line block
contains Go's canonical `// Code generated ... DO NOT EDIT.` marker is
left untouched — this includes files where a copyright/license header
(a `//` or `/* */` block) precedes the marker, common for
`addlicense`/`goheader` output. `goimports` itself has no awareness of
that convention, so this hook adds the guard itself.
- **Fix in place.** Formatting and import changes are applied silently — no
advisory noise on a successful fix, the same posture as a successful
`ruff-format`/`typos-format` autofix pass.
- **Groups local imports using your module's own path.** When a `go`
toolchain is on `PATH`, the hook resolves the edited file's own module
path (`go list -m`) and passes it as goimports' `-local` grouping prefix,
so your package's own internal imports stay in their own group instead of
being collapsed into the third-party group — matching goimports' own
`-local` convention without adding any new consumer config. Falls back to
goimports' plain default grouping when `go` is absent or the file isn't
in a resolvable module.
- **Syntax errors surface as advisory findings.** When `goimports` can't
parse the file, the parse diagnostic is reported via `additionalContext`,
never auto-"fixed" and never treated as a tool break.
- **Advisory, never blocking.** The hook always exits `0`. Findings are
reported via `additionalContext`; they never reject the edit. Make a
commit hook or CI your hard gate.

## Requirements

- **Bash** — the hook is a Bash script. On native Windows, install
[Git for Windows](https://code.claude.com/docs/en/setup#set-up-on-windows) so
Claude Code can run it under Git Bash.
- **jq** on `PATH` — parses the hook payload. Absent: the hook skips with a
visible once-per-session notice. [Install jq](https://jqlang.org/download/).
- **goimports** on `PATH`. Like `typos-format`, `goimports` has no
per-repo dependency-manager convention — it is conventionally
`go install`ed to the machine-global `$GOPATH/bin`. It is never
downloaded on the fly; if it is not present, the hook skips with a
visible once-per-session notice.
[Install](https://pkg.go.dev/golang.org/x/tools/cmd/goimports):
`go install golang.org/x/tools/cmd/goimports@latest` (requires a
[Go toolchain](https://go.dev/dl/)).
- **`go` on `PATH` (optional).** Used only to resolve the `-local` grouping
prefix (`go list -m`). Absent: the hook still formats/fixes imports, just
without the `-local` grouping (goimports' plain default behavior).

The hook itself runs on Bash 3.2+. Telemetry timing uses `EPOCHREALTIME`
(Bash 5.0+); on older bash the telemetry envelope is skipped while
formatting still runs.

## Install

```shell
/plugin marketplace add melodic-software/claude-code-plugins
/plugin install go-format@melodic-software
```

Then verify prerequisites with `/go-format:setup check`.

## Configuration

There are no rules to configure — `goimports` runs with no consumer-config
surface to read. One `userConfig` option tunes the hook itself:

| Option | Default | Effect |
|--------|---------|--------|
| `go_format_enabled` | `true` | Kill switch — set `false` for a clean no-op. |

Set it interactively with `/plugin configure go-format`, or headless on the
install command:

```shell
claude plugin install go-format@melodic-software --config go_format_enabled=false
```

These options are user-scoped (stored in your user settings, not the
project's). To turn the plugin off for a single repository, disable it in
that project's `enabledPlugins` instead.

## License

MIT (SPDX-License-Identifier: MIT).
Loading
Loading