Skip to content

NextStat/GoGuard

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

GoGuard

Mathematical dataflow security for Go + TypeScript.

GoGuard is a high-performance static analysis engine that catches nil/null dereferences, unhandled errors, concurrency hazards, resource leaks, and security vulnerabilities — before runtime.

Built with a Rust analysis core consuming Go's official SSA via a FlatBuffers bridge (Go → IR → Rust), GoGuard supports fast incremental analysis and AI-agent workflows via the Model Context Protocol (MCP).

Open source. MIT / Apache-2.0.

Created by the NexStat Project.


Table of Contents


Why GoGuard?

Go's compiler catches syntax and type errors but permits an entire class of runtime panics and subtle bugs:

Problem Example What happens
Nil pointer dereference user, _ := GetUser(id); fmt.Println(user.Name) panic at runtime
Silently ignored error os.Open("/etc/passwd") Bug hidden forever
Data race go func() { count++ }() Intermittent corruption
Goroutine leak go func() { for { ... } }() Memory leak, OOM
Resource leak f, _ := os.Open(path) — no defer f.Close() File descriptor exhaustion
SQL injection db.Query("SELECT * FROM users WHERE id=" + input) Security breach

GoGuard can catch these issues statically using abstract interpretation (fixed-point forward dataflow analysis) over Go's SSA form. Results are conservative: the goal is to minimize both false negatives and false positives, but there are tradeoffs.

Key Features

  • 22 analysis rules across 6 categories (nil, error, concurrency, ownership, exhaustiveness, taint)
  • Fast incremental analysis — powered by Salsa and SHA-256 bridge caching
  • Diff-aware mode — analyze only packages affected by your git changes
  • AI-native — first-class MCP server for Claude Code, Cursor, Windsurf, Codex, Zed, OpenCode
  • Auto-fix orchestrator — autonomous analyze → fix → build → test → repeat loop
  • Code Mode — agents write JavaScript to query IR, call graphs, and diagnostics
  • SARIF output — integrates with GitHub Security tab, CodeQL, SonarQube
  • Zero-copy FlatBuffers bridge — Go's go/ssa does parsing, Rust does analysis
  • Python SDK — subprocess wrapper for non-MCP agents

Installation

From Source (Rust + Go required)

# Clone
git clone https://github.com/NextStat/GoGuard.git
cd GoGuard

# Build Rust core
cargo build --release

# Build Go bridge
cd goguard-go-bridge && go build -o goguard-go-bridge && cd ..

# Install both binaries
cp target/release/goguard /usr/local/bin/
cp goguard-go-bridge/goguard-go-bridge /usr/local/bin/

From GitHub Releases

Download pre-built binaries for your platform from Releases:

# macOS (Apple Silicon)
curl -sSL https://github.com/NextStat/GoGuard/releases/latest/download/goguard-darwin-arm64.tar.gz | tar xz
sudo mv goguard goguard-go-bridge /usr/local/bin/

# macOS (Intel)
curl -sSL https://github.com/NextStat/GoGuard/releases/latest/download/goguard-darwin-amd64.tar.gz | tar xz
sudo mv goguard goguard-go-bridge /usr/local/bin/

# Linux (x86_64)
curl -sSL https://github.com/NextStat/GoGuard/releases/latest/download/goguard-linux-amd64.tar.gz | tar xz
sudo mv goguard goguard-go-bridge /usr/local/bin/

Self-Update

goguard update

Verify Installation

goguard --version
# goguard 0.1.0 (abc1234)

Prerequisite: Go toolchain (1.22+) must be installed. GoGuard uses go/packages under the hood via the bridge binary.


Quick Start

# Navigate to any Go project
cd ~/my-go-project

# Initialize GoGuard (creates goguard.toml + AGENTS.md + CLAUDE.md + Agent Skills)
goguard init

# Analyze your code
goguard check ./...

# See what changed since last commit
goguard check --diff ./...

# Get a detailed explanation of any rule
goguard explain NIL001

# Auto-fix all critical issues (with test verification)
goguard auto-fix --severity critical --test

# Output SARIF for CI/GitHub Security tab
goguard check --format sarif ./... > results.sarif

Example output:

  ⚠ NIL001 handler.go:18:22 — nil pointer dereference
    user may be nil (from GetUser return)
    confidence: 0.95

  ✗ ERR001 server.go:42:5 — error return value not checked
    db.Close() returns error, which is ignored

  ⚠ TAINT001 api.go:55:12 — SQL injection
    tainted data flows from r.URL.Query().Get("id") to db.Query()

Found 3 issues (1 critical, 1 error, 1 warning) in 0.14s

CLI Reference

goguard check

Analyze Go packages for safety issues.

goguard check [OPTIONS] [PACKAGES...]

Arguments:

Argument Default Description
PACKAGES ./... Go packages to analyze

Options:

Flag Default Description
--diff off Only analyze packages with changed .go files in git worktree
--format <FMT> human Output format: human, json, sarif, markdown (or md)
--severity <SEV> (all) Minimum severity to report: info, warning, error, critical
--max-diagnostics <N> 100 Maximum diagnostics to report (0 = unlimited)
--strict-params off Treat nilable params as MaybeNil (more findings, may add false positives)
--no-cache off Disable bridge cache
--cache-dir <DIR> auto Override bridge cache directory
--no-color off Disable colored output

Examples:

# Analyze entire project
goguard check ./...

# Only critical issues, JSON output
goguard check --severity critical --format json ./...

# CI pipeline — SARIF for GitHub Security tab
goguard check --format sarif ./... > results.sarif

# Diff-aware (only changed packages) — perfect for pre-commit hooks
goguard check --diff ./...

# Analyze a specific package
goguard check ./internal/handler

# Strict nil checking (catches more bugs, may have false positives)
goguard check --strict-params ./...

# Markdown output for AI agents
goguard check --format md ./...

Exit codes:

Code Meaning
0 No issues found
1 Issues found
2 Usage error

goguard auto-fix

Autonomous fix loop: analyze → generate fix → apply → go buildgo test → repeat.

goguard auto-fix [OPTIONS] [PACKAGES...]

Options:

Flag Default Description
--severity <SEV> error Minimum severity to fix
--max-iterations <N> 10 Maximum fix loop iterations
--max-fixes <N> 50 Maximum number of fixes to apply
--max-time-secs <N> 300 Time budget in seconds (0 = unlimited)
--test off Run go test after each iteration
--dry-run off Preview fixes without applying
-v, --verbose off Show detailed progress

Examples:

# Fix all critical issues, verify with tests
goguard auto-fix --severity critical --test

# Preview what would be fixed (no changes)
goguard auto-fix --dry-run

# Quick mode — fix up to 5 issues, no tests, 60s budget
goguard auto-fix --max-fixes 5 --max-time-secs 60

# Fix a specific package
goguard auto-fix ./internal/handler

# Verbose output to see each iteration
goguard auto-fix -v --test

How it works:

  1. Analyze the project
  2. Prioritize diagnostics (critical → error → warning, respecting dependency order)
  3. Generate and apply the fix (code edits)
  4. Run go build ./... — on failure, rollback the fix and skip
  5. Optionally run go test ./... — on failure, rollback and skip
  6. Repeat until budget exhausted or no more fixable issues

Example output:

Iteration 1/10: analyzing...
  Fixed NIL001 handler.go:18 — added nil check
  go build: OK
  go test: OK (47 pass, 0 fail, 3 skip)

Iteration 2/10: analyzing...
  Fixed ERR001 server.go:42 — added error handling
  go build: OK
  go test: OK

Result: 2 fixes applied, 0 skipped
  Before: { critical: 3, error: 5, warning: 8 }
  After:  { critical: 1, error: 4, warning: 8 }
  Build: pass | Tests: 47 pass, 0 fail
  Time: 12.4s

goguard fix

Generate and optionally apply a fix for a specific diagnostic.

goguard fix <DIAGNOSTIC_ID> [OPTIONS]

Options:

Flag Description
--apply Write fix directly to disk
--patch Output unified diff (pipe to patch -p0)
--verify Re-analyze after applying to confirm the fix works

Examples:

# Show the fix (preview)
goguard fix "NIL001-handler.go:18"

# Apply and verify
goguard fix "NIL001-handler.go:18" --apply --verify

# Generate a patch file
goguard fix "NIL001-handler.go:18" --patch > fix.patch
patch -p0 < fix.patch

goguard explain

Print a detailed explanation of any rule, including examples and fixes.

goguard explain <RULE>

Examples:

goguard explain NIL001
goguard explain ERR001
goguard explain TAINT001
goguard explain OWN004

Example output:

NIL001: Nil pointer dereference

A value that may be nil is used in a context that would cause a
runtime panic (field access, method call, index, etc.).

Example:
  user, _ := GetUser(id)
  fmt.Println(user.Name) // user may be nil

Fix: Check for nil before use:
  if user != nil {
      fmt.Println(user.Name)
  }

goguard query

Run GoGuard QL queries against analysis results. Supports interactive REPL mode.

goguard query [OPTIONS] [EXPRESSION]

Options:

Flag Description
--repl Interactive mode — analyze once, run multiple queries
--project-dir <DIR> Project directory (default: current)

Examples:

# Single query
goguard query 'diagnostics where severity == "critical"'

# Interactive REPL
goguard query --repl

# Inside the REPL:
> diagnostics where severity == "critical"
> diagnostics where rule == "NIL001"
> count
> callers of "(*Server).handleRequest"
> taint paths from "http.Request" to "database/sql"
> help
> quit

GoGuard QL syntax:

Query Description
diagnostics List all diagnostics
diagnostics where severity == "critical" Filter by severity
diagnostics where rule == "NIL001" Filter by rule
diagnostics where file contains "handler" Filter by filename
count Count current diagnostics
callers of "pkg.FuncName" Show callers in the call graph
taint paths from "source" to "sink" Trace taint propagation
help Show all commands

goguard init

Initialize GoGuard in the current project (one-time setup).

Creates:

  • goguard.toml
  • AGENTS.md (if missing)
  • CLAUDE.md (if missing)
  • First-party agent guidance (SKILL.md + Cursor rules + Windsurf workflows) installed by goguard init
goguard init

If goguard.toml already exists, goguard init exits with an error (it will not overwrite). For existing projects, use goguard skills install and goguard update-agents-md.

See Configuration for all options.


goguard skills install

Install (or update) first-party Agent Skills into a project.

goguard skills install [--project-dir <DIR>] [--targets <LIST>] [--update true|false]
  • --targets is a comma-separated list: github, claude, opencode, agents, windsurf, or all.
  • Default targets are claude,opencode,agents.

Examples:

# Update/reinstall skills in default locations
goguard skills install --update

# Also install into Windsurf + visible repo tree
goguard skills install --targets cursor,windsurf,github --update

goguard setup

Print ready-to-copy MCP/LSP configuration for your AI tool or editor.

goguard setup <TARGET>

Supported targets: claude-code, cursor, windsurf, codex, zed, opencode, vscode

# Print config for Claude Code
goguard setup claude-code

# Print config for Cursor
goguard setup cursor

See AI Agent Integration for full setup instructions.


goguard serve

Start GoGuard as a long-running server (MCP or LSP).

goguard serve [OPTIONS]
Flag Description
--mcp Start as MCP server (for AI agents)
--lsp Start as LSP server (for editors)
# MCP server (usually called by the AI tool, not directly)
goguard serve --mcp

# LSP server
goguard serve --lsp

goguard update

Self-update GoGuard to the latest version from GitHub Releases.

goguard update

goguard update-agents-md

Update or create the GoGuard section in your project's AGENTS.md file, providing AI agents with context about your project's analysis results and conventions.

goguard update-agents-md [--path AGENTS.md]

goguard sdk

SDK generation and CLI tool interface for non-MCP integrations.

# Generate Python SDK
goguard sdk generate python

# Call an MCP tool via CLI (for SDK integration)
goguard sdk call <TOOL> --params '<JSON>' [--project-dir <DIR>]

Examples:

# Analyze via SDK call
goguard sdk call goguard_analyze --params '{"packages": ["./..."]}'

# Explain a rule
goguard sdk call goguard_explain --params '{"rule": "NIL001"}'

# Fix a diagnostic
goguard sdk call goguard_fix --params '{"diagnostic_id": "NIL001-handler.go:18"}'

Configuration

goguard.toml Reference

GoGuard looks for goguard.toml in the current directory and walks up parent directories. Create one with goguard init.

[goguard]
# Minimum severity to report: "info", "warning", "error", "critical"
severity_threshold = "warning"

# Skip files starting with "// Code generated" (default: true)
skip_generated = true

# Maximum diagnostics to report (0 = unlimited)
# max_diagnostics = 0

# Bridge cache directory (auto-detected if omitted)
# cache_dir = "~/.cache/goguard/bridge-cache"

# Maximum cached bridge outputs to retain
# max_cache_entries = 20

# Disable bridge caching entirely
# no_cache = false


# ───────────────────────────────────────────────
# Nil Safety
# ───────────────────────────────────────────────
[rules.nil]
enabled = true

# Strict parameter mode (default: false).
# When false: all pointer parameters are assumed NonNil (fewer reports, may miss bugs).
# When true:  nilable parameters start as MaybeNil. GoGuard then applies entrypoint
#             models for known frameworks (net/http, gin, echo, fiber, grpc, testing)
#             to seed handler params back to NonNil — so framework handlers stay clean,
#             but internal functions that receive nil pointers are caught.
# strict_params = false

# User-provided nil models.
# Tell GoGuard whether specific functions return nil or not.
# Values: "nonnull" (never returns nil), "nilable" (can return nil)
# For multi-return functions, append #<index>: "os.Open#0" = the *File return.
[rules.nil.models]
# "mycompany/internal/db.GetDB" = "nonnull"
# "mycompany/internal/cache.Get#0" = "nilable"
# "context.WithCancel#0" = "nonnull"


# ───────────────────────────────────────────────
# Error Checking
# ───────────────────────────────────────────────
[rules.errcheck]
enabled = true
# Glob patterns for functions whose error returns can be safely ignored
ignore = ["fmt.Print*", "fmt.Fprint*"]


# ───────────────────────────────────────────────
# Concurrency Analysis
# ───────────────────────────────────────────────
[rules.concurrency]
enabled = true


# ───────────────────────────────────────────────
# Resource Lifecycle / Ownership
# ───────────────────────────────────────────────
[rules.ownership]
enabled = true


# ───────────────────────────────────────────────
# Exhaustiveness Checking
# ───────────────────────────────────────────────
[rules.exhaustive]
enabled = true


# ───────────────────────────────────────────────
# Taint Analysis (Security)
# ───────────────────────────────────────────────
[rules.taint]
enabled = true

Nil Models

Nil models let you tell GoGuard about the nil-return behavior of functions it can't analyze (external packages, C bindings, etc.).

[rules.nil.models]
# Single-return: function never returns nil
"mycompany/pkg.NewClient" = "nonnull"

# Multi-return: the *File at index 0 is never nil when err==nil
# (GoGuard already handles the Go error convention for stdlib,
#  but for your own code you may need to specify)
"mycompany/pkg.Open#0" = "nonnull"

# Explicitly mark a function as possibly returning nil
"mycompany/pkg.FindUser#0" = "nilable"

Built-in stdlib models (no config needed):

GoGuard ships with models for common stdlib functions including context.Background(), context.TODO(), context.WithCancel(), context.WithTimeout(), context.WithValue(), bytes.NewBuffer(), bytes.NewBufferString(), strings.NewReader(), errors.New(), fmt.Errorf(), json.NewEncoder(), json.NewDecoder(), and more.

Inline Annotations

Suppress a specific diagnostic on the next line or the same line:

//goguard:nonnull
user := GetUser(id) // GoGuard will treat this as non-nil

result := riskyCall() //goguard:nonnull

Note: Annotations work by reading the Go source file from disk. The file path must be resolvable from the working directory.


Analysis Rules

Nil Safety

Rule Severity Description
NIL001 Critical Nil pointer dereference. A value that may be nil is used in a context that would cause a runtime panic (field access, method call, index, slice).
NIL002 Critical Unchecked type assertion. x.(string) without the comma-ok pattern panics if the assertion fails.
NIL004 Warning/Critical Nil map access. Reading from a nil map returns zero-value (warning). Writing to a nil map panics (critical).
NIL006 Critical Nil channel operation. Send or receive on a nil channel blocks forever, causing a goroutine deadlock.

NIL001 — Nil pointer dereference:

// ✗ BAD: user may be nil
user, _ := GetUser(id)
fmt.Println(user.Name) // ← NIL001: nil pointer dereference

// ✓ GOOD: nil check before use
user, err := GetUser(id)
if err != nil {
    return err
}
fmt.Println(user.Name) // safe

NIL002 — Unchecked type assertion:

// ✗ BAD: panics if x is not a string
s := x.(string) // ← NIL002

// ✓ GOOD: comma-ok pattern
s, ok := x.(string)
if !ok {
    return errors.New("not a string")
}

NIL004 — Nil map access:

// ✗ BAD: writing to nil map panics
var m map[string]int
m["key"] = 42 // ← NIL004: panic

// ✓ GOOD: initialize the map
m := make(map[string]int)
m["key"] = 42

Error Checking

Rule Severity Description
ERR001 Error Error return value not checked. A function returns an error, but the return is discarded.
ERR002 Warning Error assigned to blank identifier. The error is explicitly discarded with _.
// ✗ BAD: error completely ignored
os.Open("/tmp/file") // ← ERR001

// ✗ BAD: error explicitly discarded
f, _ := os.Open("/tmp/file") // ← ERR002

// ✓ GOOD: error properly checked
f, err := os.Open("/tmp/file")
if err != nil {
    return fmt.Errorf("opening file: %w", err)
}
defer f.Close()

Ignoring specific functions:

[rules.errcheck]
ignore = ["fmt.Print*", "fmt.Fprint*", "(*log.Logger).Print*"]

Concurrency

Data Races

Rule Severity Description
RACE001 Error Shared variable access in goroutine. A variable from the enclosing scope is accessed inside a goroutine without synchronization.
RACE002 Error Goroutine captures loop variable. A goroutine captures a loop variable by reference — all goroutines see the final value.
// ✗ BAD: data race on count
count := 0
go func() { count++ }() // ← RACE001

// ✓ GOOD: use atomic
var count int64
go func() { atomic.AddInt64(&count, 1) }()
// ✗ BAD: all goroutines see the last item
for _, v := range items {
    go func() { process(v) }() // ← RACE002
}

// ✓ GOOD: pass as argument
for _, v := range items {
    go func(v Item) { process(v) }(v)
}

Goroutine Leaks

Rule Severity Description
LEAK001 Warning Goroutine may never terminate. No visible termination path (no context, no channel close, no return).
LEAK002 Warning Channel created but never used. A channel is allocated with make() but never sent to or received from.
// ✗ BAD: goroutine runs forever
go func() { // ← LEAK001
    for {
        doWork()
    }
}()

// ✓ GOOD: use context for cancellation
go func(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            return
        default:
            doWork()
        }
    }
}(ctx)

Channel Issues

Rule Severity Description
CHAN001 Critical Send on possibly closed channel. Panics at runtime.
CHAN002 Warning Select without default case. May block indefinitely.

Resource Lifecycle

Rule Severity Description
OWN001 Error Resource opened but never closed. File, connection, etc. leaks.
OWN002 Critical Use after close. Resource used after Close().
OWN003 Critical Double close. Resource closed more than once — may panic.
OWN004 Warning Resource close not deferred. If code panics between open and close, the resource leaks.
// ✗ BAD: f is never closed (OWN001)
f, err := os.Open(path)
if err != nil { return err }
data, _ := io.ReadAll(f)

// ✗ BAD: not using defer (OWN004)
f, err := os.Open(path)
if err != nil { return err }
data, _ := io.ReadAll(f)
f.Close() // if ReadAll panics, f leaks

// ✓ GOOD
f, err := os.Open(path)
if err != nil { return err }
defer f.Close()
data, _ := io.ReadAll(f)

Exhaustiveness

Rule Severity Description
EXH001 Warning Type switch missing interface implementor. Not all types that implement an interface are covered.
EXH002 Warning Enum switch missing constant value. Not all enum constants are handled.
EXH003 Info Missing default case in non-exhaustive switch.
type Shape interface { Area() float64 }
type Circle struct { ... }
type Square struct { ... }
type Triangle struct { ... } // new type added

// ✗ BAD: Triangle not handled (EXH001)
switch s := shape.(type) {
case *Circle:  ...
case *Square:  ...
}

// ✓ GOOD: exhaustive or explicit default
switch s := shape.(type) {
case *Circle:   ...
case *Square:   ...
case *Triangle: ...
}

Taint Analysis

Rule Severity Description
TAINT001 Critical SQL injection. Tainted data flows to a SQL query.
TAINT002 Critical Command injection. Tainted data flows to exec.Command.
TAINT003 Error Path traversal. Tainted data flows to file path operations.
TAINT004 Error Cross-site scripting (XSS). Tainted data flows to HTML output.
// ✗ BAD: SQL injection (TAINT001)
id := r.URL.Query().Get("id")
db.Query("SELECT * FROM users WHERE id=" + id)

// ✓ GOOD: parameterized query
id := r.URL.Query().Get("id")
db.Query("SELECT * FROM users WHERE id=$1", id)
// ✗ BAD: command injection (TAINT002)
cmd := exec.Command("sh", "-c", userInput)

// ✓ GOOD: pass as separate arguments
cmd := exec.Command("grep", "-r", userInput, "/safe/dir")
// ✗ BAD: path traversal (TAINT003)
path := filepath.Join("/uploads", userInput)
os.ReadFile(path) // userInput = "../../etc/passwd"

// ✓ GOOD: validate the resolved path
path := filepath.Join("/uploads", filepath.Clean(userInput))
if !strings.HasPrefix(path, "/uploads/") {
    return errors.New("invalid path")
}

AI Agent Integration (MCP)

GoGuard exposes a full-featured MCP (Model Context Protocol) server. AI coding agents can analyze code, get explanations, apply fixes, and run queries — all programmatically.

Claude Code

# Print the config snippet
goguard setup claude-code

Add to .mcp.json in your project directory (or ~/.claude.json globally):

{
  "mcpServers": {
    "goguard": {
      "command": "/usr/local/bin/goguard",
      "args": ["serve", "--mcp"]
    }
  }
}

Cursor

goguard setup cursor

Add to .cursor/mcp.json:

{
  "mcpServers": {
    "goguard": {
      "command": "/usr/local/bin/goguard",
      "args": ["serve", "--mcp"]
    }
  }
}

Windsurf

goguard setup windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "goguard": {
      "command": "/usr/local/bin/goguard",
      "args": ["serve", "--mcp"]
    }
  }
}

Codex

goguard setup codex

Add to ~/.codex/config.toml:

[mcp_servers.goguard]
command = "/usr/local/bin/goguard"
args = ["serve", "--mcp"]

Zed

goguard setup zed

Add to ~/.config/zed/settings.json:

{
  "context_servers": {
    "goguard": {
      "command": "/usr/local/bin/goguard",
      "args": ["serve", "--mcp"]
    }
  }
}

OpenCode

goguard setup opencode

Add to opencode.json:

{
  "mcp": {
    "goguard": {
      "type": "local",
      "command": ["/usr/local/bin/goguard", "serve", "--mcp"],
      "enabled": true
    }
  }
}

VS Code (LSP)

goguard setup vscode

GoGuard can also run as an LSP server for standard editor integration:

{
  "goguard.path": "/usr/local/bin/goguard",
  "goguard.lsp.enabled": true,
  "goguard.lsp.args": ["serve", "--lsp"]
}

MCP Tools Reference

When connected as an MCP server, GoGuard exposes the following tools to AI agents:

Tool Description
goguard_analyze Run analysis on packages. Returns lightweight "skeleton" diagnostics (~50 tokens each) to preserve context window.
goguard_explain Get full details for a specific diagnostic (explanation, code context, blast radius).
goguard_fix Generate and optionally apply a fix. Auto-verifies by default.
goguard_verify Re-analyze specific files to confirm fixes work.
goguard_batch Apply fixes for multiple diagnostics in dependency order, verified once at the end.
goguard_rules List all available analysis rules with descriptions.
goguard_query Run GoGuard QL queries against analysis results.
goguard_search Explore GoGuard's API, rule catalog, IR schema, and examples. The agent's "instruction manual".
goguard_execute Run JavaScript code against analysis data (call graphs, diagnostics, IR). Code Mode.
goguard_autofix Long-running auto-fix loop with progress notifications.
goguard_snapshot Save/compare/diff analysis snapshots (before/after).
goguard_teach Teach GoGuard about a function's nil-return behavior (user model via elicitation).

Skeleton vs Full output:

goguard_analyze returns lightweight skeletons by default (~50 tokens per diagnostic), preserving the agent's context window:

{
  "id": "NIL001-handler.go:18",
  "rule": "NIL001",
  "severity": "critical",
  "title": "nil pointer dereference",
  "location": {"file": "handler.go", "line": 18, "column": 22},
  "fix_available": true
}

The agent then calls goguard_explain or goguard_fix only for diagnostics it wants to investigate — avoiding context window bloat.


Python SDK

For AI agents that don't use MCP (e.g., Python-based CodeAct agents), GoGuard provides a subprocess-based Python SDK.

Installation

pip install goguard

Usage

from goguard import GoGuard

g = GoGuard("/path/to/go/project")

# Analyze
result = g.analyze(severity="error")
for d in result.diagnostics:
    print(f"{d.rule} {d.location.file}:{d.location.line}{d.title}")

# Get full details
detail = g.explain(result.diagnostics[0].id)

# Fix a diagnostic
fix = g.fix(result.diagnostics[0].id)
fix.apply()  # writes to disk

# Auto-fix all errors
report = g.auto_fix(severity="error", dry_run=True)
print(f"Would fix {report.fixes_applied} issues")

# Run JavaScript against analysis data (Code Mode)
result = g.execute("goguard.diagnostics().length")
print(result.output)

# Query with GoGuard QL
result = g.query('diagnostics where severity == "critical"')

API Reference

Method Returns Description
analyze() AnalysisResult Run static analysis
explain(id) dict Full diagnostic details
fix(id) FixResult Generate and verify a fix
batch(...) BatchResult Batch-fix multiple diagnostics
auto_fix(...) AutoFixResult Full auto-fix orchestrator
snapshot(...) dict Save/compare analysis snapshots
rules(...) list[Rule] List available rules
search(code) SearchResult Explore API via JavaScript
execute(code) ExecuteResult Run JS against analysis data
query(expr) QueryResult GoGuard QL or JavaScript query

Architecture

┌──────────────────────────────────────────────────┐
│  goguard-go-bridge  (Go, "Fat Bridge")           │
│                                                  │
│  go/packages.Load() → go/types → go/ssa          │
│      ↓                                           │
│  SSA + CFG + Call Graph + Interface Table         │
│      ↓                                           │
│  Serialize → FlatBuffers IR                       │
└───────────────────┬──────────────────────────────┘
                    │ stdio
                    ▼
┌──────────────────────────────────────────────────┐
│  goguard  (Rust, analysis core)                  │
│                                                  │
│  Decode IR → Salsa DB                             │
│      ↓                                           │
│  Analysis passes:                                │
│    • Nil lattice (forward dataflow, fixpoint)    │
│    • Errcheck (error variable tracking)          │
│    • Concurrency (goroutine + shared state)      │
│    • Ownership (resource state machine)          │
│    • Exhaustiveness (enum/interface coverage)    │
│    • Taint (source → sink propagation)           │
│      ↓                                           │
│  Diagnostics → Formatters (human/JSON/SARIF/MD)  │
│      ↓                                           │
│  Output: CLI / MCP server / LSP server / Pipe    │
└──────────────────────────────────────────────────┘

Why two languages?

  • Go handles everything Go does best: parsing Go code, type checking, SSA construction. We use Go's official go/packages and go/ssa — battle-tested on millions of Go projects.
  • Rust handles everything Rust does best: parallel dataflow analysis, incremental caching (Salsa), rich diagnostics (ariadne), LSP/MCP server infrastructure (tower-lsp, rmcp).

The FlatBuffers bridge connects them efficiently: Go builds the typed program graph, Rust analyzes it.


Contributing

We welcome community contributions! Please read our CONTRIBUTING.md for details.

Documentation

  • Configuration Guide — Full goguard.toml reference, inline annotations, CI/CD examples
  • Analysis Rules — All 22 rules with severity, Go code examples, fix patterns
  • MCP Integration — Setup for Claude Code, Cursor, Windsurf, Codex, Zed, OpenCode, VS Code; MCP tools with parameters

Quick start:

# Run Rust tests
cargo test --workspace

# Run Go bridge tests
cd goguard-go-bridge && go test ./...

# Check formatting and lints
cargo fmt --check
cargo clippy -- -D warnings

License

Dual-licensed under MIT or Apache 2.0, at your option.

About

Zero-tolerance for Go panics. A Rust-powered static analyzer that brings mathematical compilation rigor to the Go ecosystem. Designed natively for AI Agents via MCP.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors