Prerequisites

  • Go 1.27.0 or later
  • A Go module repository (go.mod present)

Install

Homebrew (recommended)

brew install --cask ozgurcd/tap/gograph
gograph version

Go install

go install github.com/ozgurcd/gograph/cmd/gograph@latest
gograph version

Official MCP Registry / MCPB (preview)

MCPB-capable clients can discover io.github.ozgurcd/gograph in the official Registry. This installs a self-contained local MCP server bundle rather than a CLI on PATH. Select the bundle matching macOS, Linux, or Windows and the host’s amd64/arm64 architecture, then choose the root directory of the Go project to analyze. Current Registry metadata cannot select CPU architecture portably, so verify the asset filename instead of assuming automatic client selection. See Official MCP Registry for details.

From source

git clone https://github.com/ozgurcd/gograph
cd gograph
make build        # produces bin/gograph
sudo make install # copies to /usr/local/bin

Step 1 — Build the graph

Navigate to the root of any Go module and run:

gograph build .

This walks the .go files selected by the documented scanner/build-context policy, extracts their ASTs, and writes:

  • .gograph/graph.json — the machine-readable graph used by graph-backed CLI queries
  • .gograph/GRAPH_REPORT.md — master index report
  • .gograph/graph-symbols.md — all symbols
  • .gograph/graph-routes.md — HTTP routes
  • .gograph/graph-sql.md — SQL queries
  • .gograph/graph-errors.md — error declarations
  • .gograph/graph-deps.md — package dependencies
  • .gograph/graph-concurrency.md — concurrency primitives
  • .gograph/graph-config.md — environment reads
  • .gograph/graph-tests.md — test edge mapping

graph.json also stores compact security-flow facts used by gograph flow; findings and sanitizer policy are evaluated when queried rather than written as a Markdown report.

Graph/report publishers coordinate through .gograph/.artifacts.lock. They stage the graph and all nine reports, rename reports first, and rename graph.json last as the publication commit marker. Publication refuses a linked or non-directory .gograph, and readers require a regular repository-confined graph.json. Same-directory replacement is atomic on Unix-like systems but is not guaranteed atomic by Go on non-Unix platforms. The complete ten-file bundle is not a single transaction; a crash can leave newer reports beside the previous graph.json. The lock file remains as separate operational state. Consumers should treat graph.json as the authoritative marker.

.gograph/ is automatically added to the Git repository root .gitignore. Outside a Git worktree, gograph falls back to the build target .gitignore. The update accepts only an absent or regular .gitignore; it refuses a link or special file without modifying its target. Files and directories ignored by Git are excluded consistently from builds, freshness checks, and change detection. If no Go files are found, or every Go file fails to parse, the build exits without replacing an existing graph. Partial status retains parse failures and selection/security warnings in graph.json build metadata. Each successfully parsed source stores a SHA-256 digest. Subsequent builds reparse changed packages and reuse parser records for unchanged packages; precise builds still recompute repository-wide CHA/SSA. Linked directories and linked/special files for extensions recognized by go/build are reported and excluded. Unrelated regular-file or dangling links with non-Go extensions do not block precision; linked/non-regular go.mod, go.sum, go.work, go.work.sum, and vendor/modules.txt metadata is rejected before toolchain use. Applicable go.work use members may be siblings beneath the nearest real Git checkout; without one they remain beneath the workspace directory. Nested Git boundaries are not crossed, and their directories, go.mod, and optional go.sum are validated before cmd/go. An explicitly symlinked repository root remains supported. AST and query-time source reads are confined to regular files beneath that root.

Graphs with a missing or unsupported repository source-policy marker are not trusted. The current CLI and MCP startup reject those artifacts and rebuild (or ask you to run gograph build) rather than trusting source-derived or unknown-policy data already stored in them. Older binaries do not enforce this boundary and should not be used for untrusted repositories.

Precise mode

gograph build . --precise
# Fail CI if production precision falls back (artifact remains inspectable):
gograph build . --precise --strict
# Include files and tests guarded by //go:build integration:
gograph build . --precise --tags=integration

--tags accepts a validated comma-separated list and selects one graph build context; it does not union multiple builds. An explicit value replaces GOFLAGS -tags, while omitting it preserves the existing inherited behavior. The selection is fingerprinted. Start MCP with the same option (gograph mcp . --tags=integration) so all later refreshes retain it.

Attempts Go type loading plus CHA/SSA enrichment on top of the AST pass. Before its first cmd/go invocation, normal indexing validates Go tool metadata (go.mod, go.sum, go.work, go.work.sum, and vendor/modules.txt) and confines applicable workspace members to the nearest real Git checkout or, without one, their workspace directory. The scanner then excludes linked directories and linked/special recognized Go build inputs before build selection and AST reads, while ignoring unrelated non-Go file links. Before repository package type loading, the stronger preflight rejects source-tree links cmd/go may inspect across the selected root plus its effective module root, or the workspace root and member trees; .git and .gograph are excluded from that walk. Unsafe repository input makes enrichment fail closed while the safe AST graph remains available as precise_fallback. Compilable, build-selected production packages are required for precise data; if enrichment fails or omits an indexed non-test source file, gograph warns and retains the AST graph. Successful, fallback, and AST-only status is persisted as precise, precise_fallback, or ast, except that a failed retry keeps an existing fresh successful precise artifact covering the same sources. Default fallback exits zero for compatibility; --strict requires --precise and exits non-zero after artifact publication or retention. A separate non-fatal typed pass resolves direct and conservative interface test-call targets. Broken test packages yield typed_partial test attribution without downgrading successful production precision. A precise interface invocation retains every valid named in-repository CHA target, so callers Repository.Delete can resolve direct, embedded-interface, and promoted concrete methods without dropping alternative implementations. Promoted wrappers forward through traversal-only synthetic edges that do not appear as source call sites. CHA can still over-approximate runtime targets, while reflection, plugins, unsafe, test-only packages, unnamed concrete types, and module-external implementations remain incomplete. Go dependency/toolchain resolution follows the user’s environment and remains open-world. Use before major refactors or blast-radius analysis.

Typed-only test targets are recomputed during incremental precise builds rather than reused as parser facts. Persisted graph JSON larger than 512 MiB is rejected before allocation; rerun gograph build to reconstruct it from source. Production SSA bodies cover selected repository packages instead of the full dependency closure; imported types and local external-call references remain available without dependency-body call graphs and source-less wrapper noise.

When to use which:

Mode Speed Requires compilable? Interface dispatch
build . Fast No Heuristic (duck-typing)
build . --precise Slower Yes Type-checked CHA
build . --precise --strict Slower; CI-visible fallback Yes Type-checked CHA or non-zero

Step 2 — Check the index

gograph stats

Prints schema version, build timestamp, and counts:

schema_version : 2
generated_at   : 2026-05-22 18:00:00 UTC
precision      : precise
test_resolution: typed_complete
packages       : 24
files          : 187
symbols        : 1843
calls          : 6201
imports        : 412
routes         : 38
sqls           : 29
env_reads      : 14
test_edges     : 522
flow_functions : 311
build_status   : complete
parsed_files   : 187/187
reused_files   : 0
rebuilt_pkgs   : 42
parse_failures : 0
gograph stale
# For a graph built with --tags=integration:
gograph stale --tags=integration

Compares the current selected-file inventory, effective Go build context, and SHA-256 source-content digests with graph.json; modification times are diagnostic only. It uses the same build-constraint and ignore policy as build; stale and graph-backed query commands use the trusted directory from which graph.json was loaded, not its serialized root metadata, so they work identically from subdirectories. Exit 0 means current, 2 means stale, and 1 means an operational or JSON serialization error; text and --json modes use the same contract. Normally rebuild for status 2. A status-1 message that explicitly reports a missing or unsupported source-policy marker is a one-time rebuild migration; resolve other status-1 errors instead of hiding them with an automatic rebuild.

Step 3 — Run repository-wide queries

# No project-specific symbol names are required for these commands
gograph summary
gograph hotspot --top 5
gograph flow --no-tests

Choose a real function or method reported by summary, hotspot, or gograph complexity, then replace YourSymbol below with that name:

# Start with low-token discovery, then request the detail you need
gograph explore YourSymbol --compact
gograph explore YourSymbol
gograph explore YourSymbol --deep

# Read its source and surrounding graph context
gograph source YourSymbol
gograph context YourSymbol

# Who calls it?
gograph callers YourSymbol

# What does it call?
gograph callees YourSymbol

# Full blast radius
gograph impact YourSymbol

# Before editing it
gograph plan YourSymbol

explore is additive and shares gograph.explore.v1 with MCP gograph_explore. Compact defaults to 5 rows and returns discovery, identity/role, complete counts, and explicit omissions. Standard defaults to 10 and includes source/direct evidence plus exact impact. Deep defaults to 25 and adds bounded depth-3 exact callers/callees, package context, and explanation. An explicit limit overrides these defaults. Use the focused commands shown above when you need an unbounded section.

Example: Reading Symbol Source Code

The following is captured, repository-specific output from running gograph source normalizeSymbolName in the gograph repository. Your project will have different symbol names and locations:

$ gograph source normalizeSymbolName

// github.com/ozgurcd/gograph/internal/search::normalizeSymbolName (internal/search/advanced.go:12-21)
func normalizeSymbolName(name string) string {
	name = strings.TrimPrefix(name, "(")
	if idx := strings.Index(name, ")."); idx >= 0 {
		name = name[idx+2:]
	}
	if idx := strings.LastIndex(name, "."); idx >= 0 {
		name = name[idx+1:]
	}
	return strings.ToLower(name)
}

Output formats

Many result-list queries support text, JSON, and files-only output:

gograph callers Foo              # text: [kind] Name — detail  (file:line)
gograph callers Foo --json       # {"schema_version":"1","command":"callers","status":"ok","query":"Foo","count":N,"results":[...]}
gograph callers Foo --files-only # flat list of unique file paths

Successful JSON envelopes always include count; empty collection results use []. Operational failures use status: "error" and exit 1. Policy findings can make check --json exit 1 while still returning its structured report.

--files-only is implemented by query, focus, node, public, fields, embeds, imports, callers, callees, impact, implementers, envs, interfaces, concurrency, tests, routes, sql, errors, flow, orphans, mutate, constructors, literals, usages, returnusage, schema, globals, mocks, fixtures, boundaries, httpcalls, and dependents. Empty files-only results write zero lines.

Composed-analysis commands also support JSON where documented. Operational commands (build, wiki, gate, snapshot, installation, and help) remain text. version --json emits its dedicated gograph.version.v1 document, and gograph_capabilities exposes the running MCP server version. Session create/end/cleanup are text; session audit additionally supports raw JSON.

--mermaid is a global CLI output flag for callers, callees, impact, endpoint, dependents, deps, path, and coupling. Bare gograph --mermaid is shorthand for the package architecture diagram. Request only one of --json, --files-only, or --mermaid; unsupported or conflicting output flags fail instead of being silently ignored.

-i <message> / --intention <message> is also global and may appear before or after the command. When a CLI audit session is active, it is mandatory for analytical commands and is stored with command telemetry; operational and index-status commands do not require it.

Rebuilding

Graph-backed CLI analysis does not auto-update. Rebuild whenever source files change:

gograph build .           # fast rebuild, tolerates broken code
gograph build . --precise # type-checked rebuild (before big refactors)
gograph build . --precise --tags=integration # include tagged tests/files
gograph build . --precise --memory-mode=low --max-memory=1GiB
                           # same precision, lower heap priority, potentially more GC CPU

You can check whether a rebuild is needed:

gograph stale

The MCP server checks source-content digests, the selected inventory/build fingerprint, and newer persisted graphs per analysis call. After an edit it reparses changed packages while reusing unchanged package AST records. Every refresh-backed response preserves its existing text and adds machine-readable gograph.graph-state.v1 metadata through gograph.mcp-result.v1. A precise session still re-runs repository-wide CHA/SSA. If enrichment fails, the tool can serve an explicitly marked current in-memory fallback; if an ordinary refresh fails, it can serve the last trusted stale graph. Neither is silently published, and a mismatched build context still fails closed. MCP stale, default changes, and stats inspect a trusted persisted graph when present, or the startup in-memory fallback when the artifact is missing, unreadable, unsafe, or uses an unsupported source policy. CLI graph-backed --json envelopes expose the same state for their persisted result.

MCP refreshes are in-memory by default. Start with gograph mcp [path] --persist-refresh to publish successful refreshes to the latest .gograph/graph.json and nine reports. Publication uses the same .artifacts.lock and graph-last commit marker described above; it is not a bundle-atomic transaction, and the lock file remains as separate operational state. The option does not update .gitignore and is not a branch cache. Later publication failure is reported as persistence.outcome=failed while the fresh in-memory result remains usable, and is retried later without rebuilding; failure to publish a required startup auto-build prevents the server from starting. A successful publication advances the persisted baseline used by default changes. For a tagged graph, start with gograph mcp [path] --tags=integration; the server reports requested/effective tags in gograph_capabilities and retains that selection for startup, refresh, baseline, and optional publication work.

The same optional memory policy is available to MCP refreshes with gograph mcp [path] --memory-mode=low --max-memory=1GiB. The byte value is a soft Go-runtime memory target rather than a guaranteed RSS ceiling.

For visual output through MCP, set mermaid: true on gograph_callers, gograph_callees, gograph_impact, gograph_endpoint, gograph_dependents, gograph_deps, gograph_path, or gograph_coupling. The selected tool returns Mermaid flowchart text instead of its normal response.