Skip to content
cccskills
FreePublished on GitHub

go-linters

Add and validate custom Go analysis linters in gh-aw.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md3.6 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Go Linters

Use this guide when adding a new custom Go analysis linter in this repository.

For PR-driven linter generation (derive a rule from a specific pull request pattern), use .github/skills/pr-to-go-linter/SKILL.md.

Where to add a new linter

  1. Create a new package under pkg/linters/<linter-name>/.
  2. Define an analyzer in that package (exported as Analyzer).
  3. Add tests in the same package using analysistest with fixtures under testdata/src/....
  4. Register the analyzer in cmd/linters/main.go so it runs via the multichecker binary.

Build and test linters

  • Test only your linter package:
    • go test ./pkg/linters/<linter-name>/...
  • Build the custom linter runner:
    • go build ./cmd/linters
  • Run all custom linters across the repo:
    • make golint-custom

make golint-custom builds cmd/linters and runs it against ./cmd/... and ./pkg/....

Common AST pitfalls

Unwrap parenthesized expressions

Expressions wrapped in parentheses appear as *ast.ParenExpr. Unwrap expressions before asserting their AST type or comparing identifiers, so forms such as (nil) and (err) are handled like nil and err. Use the shared helper:

if ident, ok := astutil.UnwrapParenExpr(expr).(*ast.Ident); ok && ident.Name == "nil" {
	// Handle nil.
}

Match all relevant statement shapes

Semantically similar calls can appear in different statement nodes. A call that discards a result may be a bare *ast.ExprStmt or part of an *ast.AssignStmt; filtering only for one shape misses the other. Include and handle each relevant node shape:

nodeFilter := []ast.Node{(*ast.AssignStmt)(nil), (*ast.ExprStmt)(nil)}
return analyzerutil.Preorder(pass, nodeFilter, func(n ast.Node) {
	switch stmt := n.(type) {
	case *ast.AssignStmt:
		analyzeAssign(stmt)
	case *ast.ExprStmt:
		analyzeExpr(stmt)
	}
})

Before submitting a linter, check expression-shape assertions for parenthesis unwrapping and verify its node filter covers relevant equivalent syntax forms.

Coverage-aware perf gating

For linters that flag micro-optimizations (allocation/perf rules), only apply them on lines that tests actually exercise — "hot paths" — rather than on dead or rarely-executed code where the optimization brings no measurable benefit. Use the shared pkg/linters/internal/coverage package:

  1. In your analyzer file, register a -hot-threshold flag in init() (not as a var initializer, to avoid an Analyzer/run/flag initialization cycle):

    var hotThreshold *int
    
    func init() {
        hotThreshold = coverage.RegisterHotThresholdFlag(Analyzer)
    }
    
  2. Immediately before reporting a diagnostic, gate it with coverage.ShouldApply:

    if !coverage.ShouldApply(pass, node.Pos(), *hotThreshold) {
        return
    }
    

coverage.ShouldApply is permissive by default: when no coverage profile is loaded via the GH_AW_LINT_COVERAGE_PROFILE environment variable, or when hot-threshold is 0, it always returns true, preserving pre-coverage-aware behavior. Only wire this into linters whose fix has a genuine performance rationale (extra allocations, O(n²) behavior, etc.) — purely readability/style linters should not be coverage-gated.

Generating the coverage profile

go test -covermode=count -coverprofile=/tmp/coverage.out ./...
export GH_AW_LINT_COVERAGE_PROFILE=/tmp/coverage.out
make golint-custom

This profile is read once per linter-runner process. To lint only a specific subtree, scope the go test and golint-custom commands to the same package path.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Standard collaboration patterns for all squad agents — worktree awareness, decisions, cross-agent communication

The English summary is being prepared. Showing the original description.

github/gh-aw5.4KUpdated Oct 19, 2026

Shared hard rules enforced across all squad agents

The English summary is being prepared. Showing the original description.

github/gh-aw5.4KUpdated Oct 19, 2026

Route gh-aw design, creation, diagnosis, patching, active debugging, and upgrade requests to the right strategies.

The English summary is being prepared. Showing the original description.

github/gh-aw5.4KUpdated Oct 19, 2026

How to write comprehensive architectural proposals that drive alignment before code is written

The English summary is being prepared. Showing the original description.

github/gh-aw5.4KUpdated Oct 19, 2026

Upgrade gh-aw to latest gh-aw-firewall release and identify follow-up spec tasks.

The English summary is being prepared. Showing the original description.

github/gh-aw5.4KUpdated Oct 19, 2026

Review code that performs git or gh operations against repository checkouts in gh-aw, checking that the right credentials are available at the right time and that sparseness, shallowness and credential-free factors are properly considered.

The English summary is being prepared. Showing the original description.

github/gh-aw5.4KUpdated Oct 19, 2026

See all skills by github

Report a problem with this skill