antislop

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 12 Imported by: 0

README

anti-slop-go

Opinionated go/analysis rules that reject low-evidence Go patterns.

This project is a Go companion to dmmulroy/anti-slop. The upstream project targets TypeScript and JavaScript through Oxlint. This project applies the same philosophy to Go.

Status

Implementation phase. Eleven analyzers are available. Nine run by default: safetyassert (rule G01), nountypedmap (G02), noanyparam (G03), noanyreturn (G04), nolaundering (G05), noadhoctypeswitch (G06), noreflect (G07), nomonkeypatch (G08), and noerrorassert (G10). Two are opt-in. nointerfacereturn (G09) reports an interface result that every return of the body builds from one concrete type; it asks a project to change signatures. justifypanic (G11) asks for a // PANICS: comment above a panic, a log.Fatal, or an os.Exit of library code. The golangci-lint plugin keeps both off until the enable setting names them. The standalone binary and go vet -vettool read no configuration file, so they run every rule, and -nointerfacereturn=false or -justifypanic=false turns one off there. Read the specification in docs/spec:

  1. Overview: philosophy, goals, and scope.
  2. Rules: the rule catalogue with examples.
  3. Implementation: architecture, distribution, and configuration.

The idea in one paragraph

Code generators produce code that compiles but carries no evidence. A type assertion with no stated invariant, an any parameter, or a map[string]any field moves a proof obligation from the author to the reader. These rules reject such patterns. The author must decode input at its I/O boundary, keep concrete types inside the program, and write a // SAFETY: justification where an assertion is the correct tool.

Use with golangci-lint

golangci-lint loads these rules as a module plugin. A module plugin is Go code, so you build a golangci-lint binary that contains it. Put a .custom-gcl.yml in the root of your project:

version: v2.10.1
name: custom-gcl
destination: .
plugins:
  - module: github.com/JacobJNilsson/anti-slop-go
    import: github.com/JacobJNilsson/anti-slop-go/plugin
    version: v0.2.0

The import line is necessary. The registration lives in the plugin subpackage, not in the module root. The version line takes a tag of this repository; v0.2.0 is the release that this section shipped in.

Run golangci-lint custom in that directory. The command clones golangci-lint, adds this module, and writes a custom-gcl binary. It needs network access, git, and a Go toolchain that satisfies the go directive of this module (see go.mod; Go 1.26 today).

Then configure the linter in .golangci.yml:

version: "2"
linters:
  enable:
    - antislop
  settings:
    custom:
      antislop:
        type: module
        description: Rejects low-evidence Go patterns.
        original-url: github.com/JacobJNilsson/anti-slop-go
        settings:
          boundary-packages:
            - example.com/app/internal/ingest
          reflect-allow:
            - example.com/app/internal/codec
          enable:
            - nointerfacereturn
            - justifypanic
          disable:
            - nountypedmap

Eight points about this file:

  • type: module is necessary. Without it, golangci-lint looks for a shared object file.
  • antislop joins the standard group of linters, so a configuration that keeps the default linters.default: standard runs it without the linters.enable entry. The entry becomes necessary when the configuration sets linters.default: none. The example keeps it, because it states the intention.
  • All rules arrive as one linter named antislop. You select the individual rules with the plugin's own enable and disable settings, not with linters.enable. An unknown rule name in either plugin setting stops the run.
  • disable drops a rule from the default set, which holds the nine rules that the Status section names as default rules. A configuration that disables every rule is legal, and the linter then reports nothing. enable turns on an opt-in rule: nointerfacereturn and justifypanic are the opt-in rules today. A name that is on by default stops the run, because enable would do nothing for it.
  • The standalone binary and go vet -vettool read no configuration file, so they run every rule, the opt-in ones included. Each analyzer has a flag of its own there: -justifypanic=false drops one rule, and -justifypanic runs that rule alone.
  • Two settings name packages by path pattern. A pattern matches the whole import path: * holds inside one segment, ... crosses a slash, and a pattern that ends in /... names the package above it as well. The standalone binary takes the same patterns in a flag, as a comma-separated list or a repeated flag. An unknown settings key stops the run, so this file names only the keys that a rule reads today.
  • boundary-packages names the packages that decode input, which rule noadhoctypeswitch (G06) reads. A type switch on an any value is the work of such a package, so the rule accepts every one of them there. The standalone flag is -noadhoctypeswitch.boundary.
  • reflect-allow names the packages that may import reflect, which rule noreflect (G07) reads. The standalone flag is -noreflect.allow.

Run the new binary with ./custom-gcl run ./....

Supported golangci-lint versions: the plugin is verified against v2.10.1. The v2.9 line shares the same plugin register API and the same golang.org/x/tools requirement, so it works too. Earlier v2 releases are untested.

Development

Run make setup once per clone; it installs the tracked git hooks. make check is the definition of green: tidy check, vet, lint, the coverage-gate self-test, race-enabled tests behind a statement coverage gate (COVERAGE_MIN, default 90%), and the build. Read AGENTS.md before your first commit and REVIEW.md before your first pull request.

License

MIT. See LICENSE.

Documentation

Overview

Package antislop provides go/analysis analyzers that reject low-evidence Go patterns. The rule catalogue lives in docs/spec.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Analyzers

func Analyzers() []*analysis.Analyzer

Analyzers returns every analyzer this module provides, the opt-in rules included. Consumers register the full list; rule toggles happen in the consumer's configuration, not here.

One registry serves the three consumption paths of 003. The golangci-lint plugin reads a configuration file, so it applies the opt-in severity of 002 and drops such a rule until enable names it. cmd/antislop and go vet -vettool read no configuration file, so they run every rule. The reader turns one off with the -NAME=false flag that multichecker gives each analyzer.

Types

This section is empty.

Directories

Path Synopsis
analyzers
justifypanic
Package justifypanic implements rule G11 of the anti-slop rule set.
Package justifypanic implements rule G11 of the anti-slop rule set.
noadhoctypeswitch
Package noadhoctypeswitch implements rule G06 of the anti-slop rule set.
Package noadhoctypeswitch implements rule G06 of the anti-slop rule set.
noanyparam
Package noanyparam implements rule G03 of the anti-slop rule set.
Package noanyparam implements rule G03 of the anti-slop rule set.
noanyreturn
Package noanyreturn implements rule G04 of the anti-slop rule set.
Package noanyreturn implements rule G04 of the anti-slop rule set.
noerrorassert
Package noerrorassert implements rule G10 of the anti-slop rule set.
Package noerrorassert implements rule G10 of the anti-slop rule set.
nointerfacereturn
Package nointerfacereturn implements rule G09 of the anti-slop rule set.
Package nointerfacereturn implements rule G09 of the anti-slop rule set.
nolaundering
Package nolaundering implements rule G05 of the anti-slop rule set.
Package nolaundering implements rule G05 of the anti-slop rule set.
nomonkeypatch
Package nomonkeypatch implements rule G08 of the anti-slop rule set.
Package nomonkeypatch implements rule G08 of the anti-slop rule set.
noreflect
Package noreflect implements rule G07 of the anti-slop rule set.
Package noreflect implements rule G07 of the anti-slop rule set.
nountypedmap
Package nountypedmap implements rule G02 of the anti-slop rule set.
Package nountypedmap implements rule G02 of the anti-slop rule set.
safetyassert
Package safetyassert implements rule G01 of the anti-slop rule set: a single-result type assertion must carry a SAFETY comment that states the invariant which makes the panic unreachable.
Package safetyassert implements rule G01 of the anti-slop rule set: a single-result type assertion must carry a SAFETY comment that states the invariant which makes the panic unreachable.
cmd
antislop command
Command antislop runs every anti-slop analyzer as a standalone multichecker.
Command antislop runs every anti-slop analyzer as a standalone multichecker.
internal
pathmatch
Package pathmatch matches the import path of a package against the path patterns of a configuration setting.
Package pathmatch matches the import path of a package against the path patterns of a configuration setting.
signature
Package signature holds the machinery that more than one rule needs.
Package signature holds the machinery that more than one rule needs.
Package antislopplugin registers the anti-slop analyzers as a golangci-lint module plugin.
Package antislopplugin registers the anti-slop analyzers as a golangci-lint module plugin.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL