Fallow-style codebase intelligence for Go.
Gallow is a Fallow-style codebase intelligence tool for Go. It analyzes Go modules for dependency drift, unused code, module hygiene issues, complexity hotspots, duplicate code, and CI-ready quality signals.
Gallow is inspired by Fallow's codebase-intelligence model. It is not the official Fallow project, and it is built specifically for Go modules.
Go already has excellent quality tools. Gallow is intended to sit beside them by combining repo-wide hygiene signals into one workflow, especially for module drift, dead code, baselines, audit output, and CI adoption.
| Tool | Primary job | Where Gallow fits |
|---|---|---|
go vet |
Correctness and suspicious code | Gallow adds repo-wide dependency, dead-code, hygiene, and reporting checks. |
staticcheck |
Go static analysis | Gallow focuses on codebase-level drift and adoption workflows rather than individual diagnostics. |
go mod tidy |
Module cleanup | Gallow runs read-only go mod tidy -diff and reports drift without mutating files. |
golangci-lint |
Lint aggregation | Gallow is a focused analyzer with baselines, audit mode, and CI output formats. |
| Gallow | Repo-wide dependency drift, dead code, module hygiene, baselines, CI and audit reporting | Use it when you want one conservative pass over module and codebase health. |
- Unused direct
requireentries ingo.mod. - External imports used in code but missing from
go.mod. - Dependencies used only from
*_test.gofiles. - Unused internal packages, files, functions, methods, structs, fields, interfaces, type aliases, vars, and consts.
- Complexity findings above configured cyclomatic or cognitive thresholds.
- Duplicate code windows across Go files.
- Read-only
go mod tidy -diffdrift detection. - Suspicious local
replacedirectives that do not point at a discovered sibling module. - Conventional Go
tooldirectives andtools.goimports. - Nested Go module analysis with workspace filters and build tags.
- Baselines, inline suppressions, coverage annotation, audit mode, and CI formats.
Install the CLI:
go install github.com/dominicnunez/gallow/cmd/gallow@latestRun it from a Go module:
gallow --root .
gallow --summary
gallow --format json
gallow --ci
gallow audit --base origin/main --format sarifWhen working from a checkout of this repository, use:
go run ./cmd/gallow --root . --summarygallow [dead-code|audit] [flags] [root]Common flags:
--root,-r: root directory to scan, default..--config,-c: config file path.--format,-f:human,json,sarif,codeclimate,gitlab-codequality, orannotations, defaulthuman.--production: exclude*_test.gofiles.--all-requires: also check// indirectrequirements for unused status.--ignore-generated: skip files with generated-code headers.--summary: print only counts in human output.--max-cyclomatic: enable cyclomatic complexity findings above this threshold.--max-cognitive: enable cognitive complexity findings above this threshold.--workspace: comma-separated module path or directory filters.--tags: comma-separated Go build tags.--coverage: Go coverage profile to annotate findings.--base,--changed-since: base ref foraudit.--fail-on-issues: exit with status 1 when findings exist.--ci: equivalent to--fail-on-issues.--baseline: suppress findings recorded in a baseline file.--save-baseline: write current findings to a baseline file.
Gallow loads .gallowrc.json from the selected root when present. Use --config <path> to load a different file. CLI flags override config values.
{
"format": "json",
"production": true,
"workspace": ["github.com/acme/service"],
"buildTags": ["integration"],
"ignorePatterns": ["internal/generated/**"],
"ignoreFindings": [
{"type": "duplicate-code", "file": "**/*_test.go"},
{"type": "complexity", "file": "internal/parser.go", "symbol": "parseArchiveFormat"}
],
"health": {
"maxCyclomatic": 20,
"maxCognitive": 15
},
"rules": {
"unused-function": "off",
"unused-field": "warn"
}
}Rule severities are off, warn, and error. The current CLI treats warn and error as reportable findings; off disables matching findings.
Use ignoreFindings for known acceptable findings without ignoring every finding in a file. Each entry matches only the fields provided. file supports the same glob patterns as ignorePatterns; other fields match exactly, including type, symbol, package, module, importPath, receiver, struct, and fingerprint.
Human output is compact:
example.com/app (.)
unused dependency github.com/acme/old v0.4.0 at go.mod:12
go mod tidy drift at go.mod:1
complex function example.com/app/internal/api.Handle at internal/api/handler.go:42 (cyclomatic 22, cognitive 31)
Summary
modules: 1
findings: 3
unused dependencies: 1
complexity findings: 1
GitHub annotation output includes warning severity:
::warning file=go.mod,line=12::unused-dependency: github.com/acme/old
::warning file=go.mod,line=1::tidy-drift
::warning file=internal/api/handler.go,line=42::complexity: Handle
Suggested actions are currently documented by finding type rather than emitted as a separate machine-readable field.
| Finding type | Suggested action |
|---|---|
unused-dependency |
Remove the unused requirement or confirm it is intentionally kept. |
unlisted-dependency |
Add the dependency with go get or remove the import. |
tidy-drift |
Run go mod tidy and review the diff. |
local-replace |
Remove the local replace or point it at a checked-in sibling module. |
complexity |
Split or simplify the function if the threshold reflects your team policy. |
duplicate-code |
Consider extracting shared logic when the duplicated block is intentional code, not test setup. |
Gallow uses stable finding type IDs as SARIF ruleId values:
| Rule ID | Meaning |
|---|---|
unused-dependency |
Direct module requirement appears unused. |
unlisted-dependency |
External import has no matching direct requirement. |
test-only-dependency |
Dependency is only used from tests. |
unused-package |
Internal package is unreachable. |
unused-file |
Go file declarations appear unused. |
unused-function, unused-method |
Function or method appears unused. |
unused-struct, unused-interface, unused-type |
Type declaration appears unused. |
unused-var, unused-const, unused-field |
Package value or field appears unused. |
complexity |
Function exceeds configured complexity thresholds. |
duplicate-code |
Repeated Go code window was found. |
tidy-drift |
go mod tidy -diff would change module files. |
local-replace |
Local replace does not point at a discovered sibling module. |
tool-dependency |
Go tool directive has no matching requirement. |
Gallow supports json, sarif, codeclimate, gitlab-codequality, and GitHub annotations output.
Run the same command locally and in CI:
gallow --root . --summary --ciUse audit mode to scope findings to changed files:
gallow audit --base origin/main --format sarifCoverage profiles from go test -coverprofile=coverage.out ./... can annotate matching findings:
gallow --coverage coverage.out --format jsonUse SARIF upload for GitHub's Code Scanning UI. Generate SARIF without --ci so alerts can be uploaded even when findings exist. Keep --ci as a separate build gate when you want findings to fail the workflow.
name: Code Scanning
on:
push:
pull_request:
permissions:
actions: read
contents: read
security-events: write
jobs:
gallow:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- run: go run ./cmd/gallow --root . --format sarif > gallow.sarif
- uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: gallow.sarif
category: gallowGallow's SARIF output includes rule metadata, stable rule IDs, deterministic SARIF levels, related locations for multi-location findings, and Gallow fingerprints for alert continuity.
Use inline comments for intentional exceptions:
// gallow-ignore-next-line unused-function
func RuntimeHook() {}
// gallow-ignore-fileUse baselines to adopt Gallow incrementally:
gallow --save-baseline gallow-baseline.json
gallow --baseline gallow-baseline.json --fail-on-issuesDead-code analysis in Go is conservative and difficult. Gallow prefers conservative findings over noisy false positives.
Areas that can affect precision include reflection, generated code, build tags, exported APIs, framework conventions, interface usage, test-only references, and //go:linkname.
- Richer SARIF and code scanning integration.
- Improved dead-code confidence levels.
- Better monorepo and workspace support.
- LSP and MCP integration.
- More precise generated-code handling.
- Release binaries through GitHub Releases.
Before opening a change, run:
go fmt ./...
go test ./...
go vet ./...
go run ./cmd/gallow --root . --summary --ciKeep changes small and verify README examples against implemented flags.
Gallow is available under the MIT License. See LICENSE.