goast [](https://github.com/m-mizutani/goast/actions/workflows/test.yml)[](https://github.com/m-mizutani/goast/actions/workflows/goast.yml)[](https://github.com/m-mizutani/goast/actions/workflows/gosec.yml) [](https://github.com/m-mizutani/goast/actions/workflows/trivy.yml)
July 4, 2026 · View on GitHub
Go AST based static analysis for Go, with rules written as Rego policies. Encode your team's own conventions once and enforce them in CI.
Motivation
Go has many excellent static analysis tools, but they check common best
practices. Every team also has its own rules — internal conventions, "this
resource must be initialized first", "use our error wrapper, not fmt.Errorf" —
that a generic linter cannot know about. goast splits a linter into
implementation (goast itself) and policy (Rego you write), so you can express
those rules yourself. It runs OPA/Rego over
the Go AST, one node at a time.
Features
- Evaluate Go source against Rego policies you control
- Report findings as text or JSON (compatible with reviewdog)
- Test policies against sample files declaratively (
goast test), so rules can't drift - Dump the Go AST as JSON to discover exactly what your policy should match
Getting started
Install with Homebrew:
brew install m-mizutani/tap/goast
Or install with go install (pre-built binaries for Linux, macOS, and Windows
are also on each GitHub Release):
go install github.com/m-mizutani/goast/cmd/goast@latest
Write a policy in package goast. Each rule matches one AST node and adds to the
fail set. This one forbids fmt.Println:
package goast
fail contains res if {
input.Kind == "ExprStmt"
input.Node.X.Fun.X.Name == "fmt"
input.Node.X.Fun.Sel.Name == "Println"
res := {
"msg": "do not use fmt.Println",
"pos": input.Node.X.Fun.X.NamePos,
"sev": "ERROR",
}
}
Evaluate a file (or a directory, or ./...) against it:
$ goast eval -p ./policy/do_not_use_println.rego examples/println/main.go
[examples/println/main.go:6] - do not use fmt.Println
fmt.Println("hello")
~~~~~~~~~~~~~~~~~~~~
Detected 1 violations
Pass --fail to make violations exit non-zero — that is your CI gate.
How it works
goast parses each Go file into a go/ast tree and evaluates the query
data.goast.fail against every node, with the node as input. A policy is
therefore a set of pattern matches over single nodes: input.Kind is the node
type, input.Node is the node itself, and each match returns a {msg, pos, sev}
result. Use goast dump to see the exact shape of any node.
Documentation
- docs/usage.md — full CLI reference:
eval,test,dump,sync, and every flag. - docs/configuration.md — the
.goast.tomlschema ([eval]/[test]) and flag precedence. - docs/ci.md — wiring goast into GitHub Actions, exit codes, and reviewdog PR comments.
- docs/examples.md — complete, runnable policies that enforce organization-specific conventions.
- goast-policy skill — deep guide to writing Rego policies (AST input format, node shapes, recipes).
Claude Code Skill
This repository ships a Claude Code skill,
goast-policy, that guides Claude through writing and testing goast policies.
Install it as a plugin:
/plugin marketplace add m-mizutani/goast
/plugin install goast-policy@goast
Then ask Claude to write a policy (e.g. "write a goast policy that forbids
fmt.Println"), or read skills/goast-policy/SKILL.md.
License
Apache License v2