references/cli.md
# `gopls` CLI reference
The Go team documents this interface as experimental — "not efficient, complete, flexible, or officially supported." Treat it as a debugging and one-shot-scripting fallback, not the primary way to drive `gopls`; prefer the MCP tools or the native `LSP` tool when either is available (see [mcp.md](mcp.md)).
## Table of contents
- [Position syntax](#position-syntax)
- [Global flags](#global-flags)
- [Shared write flags](#shared-write-flags)
- [Navigation commands](#navigation-commands)
- [Diagnostics](#diagnostics)
- [Transformation commands](#transformation-commands)
- [Code actions and code lenses](#code-actions-and-code-lenses)
- [Introspection](#introspection)
- [CodeAction kind reference](#codeaction-kind-reference)
## Position syntax
Two interchangeable formats locate a point in a file:
- `file.go:line:column` — both 1-indexed; columns count UTF-8 bytes, not runes or UTF-16 code units. Non-ASCII lines can disagree with what an editor reports if the editor counts differently.
- `file.go:#1234` — a 0-indexed byte offset from the start of the file.
```bash
gopls definition internal/cmd/definition.go:44:47
gopls definition internal/cmd/definition.go:#1270
```
## Global flags
Flags accepted by `gopls` itself, before the subcommand:
| Flag | Value | Purpose |
| --- | --- | --- |
| `-logfile=<path>` | a file path, or the literal string `auto` | Log destination; `auto` picks a default output file instead of stderr |
| `-profile.cpu=<path>` | a file path | Write a CPU profile to this file |
| `-profile.mem=<path>` | a file path | Write a memory profile to this file |
| `-profile.alloc=<path>` | a file path | Write an allocation profile to this file |
| `-profile.block=<path>` | a file path | Write a blocking-profile to this file |
| `-profile.trace=<path>` | a file path | Write an execution trace to this file |
| `-v`, `-verbose` | boolean flag, no value | Verbose output |
| `-vv`, `-veryverbose` | boolean flag, no value | Very verbose output |
`gopls mcp` accepts its own, narrower flag set: `-listen=<addr>` (run over SSE/HTTP instead of stdio), `-logfile=<path>` (defaults to stderr), and `-rpc.trace` (cannot be combined with `-listen`).
## Shared write flags
Every command that can modify source (`format`, `imports`, `rename`, `codeaction`, `codelens`, `execute`) accepts this same set — each is a boolean flag, no value:
| Flag | Purpose |
| --- | --- |
| `-w`, `-write` | Write the edited content back to the source file(s) |
| `-d`, `-diff` | Print a unified diff instead of writing |
| `-l`, `-list` | Print only the names of the files that would be/were edited |
| `-preserve` | Combined with `-w`: keep a copy of each original file before overwriting |
None of these are mutually exclusive with each other; passing none of them just computes the edit without printing or writing it.
## Navigation commands
| Command | Flags | Example | Notes |
| --- | --- | --- | --- |
| `definition` | `-json` (boolean), `-markdown` (boolean) | `gopls definition helper/helper.go:8:6` | `-json` for structured output, `-markdown` to render doc comments as Markdown |
| `references` | `-d`, `-declaration` (boolean) | `gopls references helper/helper.go:8:6` | Includes the declaration itself in the results when set |
| `implementation` | none | `gopls implementation helper/helper.go:8:6` | — |
| `call_hierarchy` | none | `gopls call_hierarchy helper/helper.go:8:6` | Static calls only |
| `symbols` | none | `gopls symbols helper/helper.go` | File-scoped outline |
| `workspace_symbol` | `-matcher=<value>` — one of `fuzzy`, `fastfuzzy`, `casesensitive`, `caseinsensitive` (default `caseinsensitive`) | `gopls workspace_symbol -matcher fuzzy 'wsymbols'` | Matching algorithm for the query |
| `signature` | none | `gopls signature helper/helper.go:8:6` | Function signature at position |
| `highlight` | none | `gopls highlight helper/helper.go:8:6` | Same-symbol identifier highlights |
| `folding_ranges` | none | `gopls folding_ranges helper/helper.go` | Collapsible regions |
| `links` | `-json` (boolean) | `gopls links internal/cmd/check.go` | Structured output when set |
| `prepare_rename` | none | `gopls prepare_rename helper/helper.go:8:6` | Validates a rename is possible at this position before attempting it |
| `semtok` | none | `gopls semtok internal/cmd/semtok.go` | Semantic token dump |
## Diagnostics
| Command | Flags | Example |
| --- | --- | --- |
| `check` | `-severity=<value>` — one of `hint`, `info`, `warning`, `error` (default `warning`); reports diagnostics at or above this severity | `gopls check -severity=error internal/cmd/check.go` |
## Transformation commands
All of these additionally accept the [shared write flags](#shared-write-flags) above.
| Command | Positional args | Example | Notes |
| --- | --- | --- | --- |
| `format` | one or more `<filerange>` (a file, or a range within one) | `gopls format -w internal/cmd/check.go` | Canonical `gofmt`-equivalent; ignores client formatting options |
| `imports` | `<filename>` | `gopls imports -w internal/cmd/check.go` | Adds/removes/sorts imports |
| `rename` | `<position> <new-name>` | `gopls rename helper/helper.go:8:6 Foo` | `<new-name>` is a plain identifier — validate first with `prepare_rename` if unsure |
## Code actions and code lenses
`codeaction` and `codelens` additionally accept the [shared write flags](#shared-write-flags).
| Command | Extra flags | Notes |
| --- | --- | --- |
| `codeaction` | `-kind=<value>` — comma-separated list of kinds, see [CodeAction kind reference](#codeaction-kind-reference) below; `-title=<regex>` — filter actions by title; `-exec` (boolean) — execute the first match instead of only listing | `-kind=refactor` matches every kind nested under it (kinds are hierarchical); only one action executes per invocation — there is no conflict resolution for applying more than one; actions of kind `source.test` are excluded unless explicitly requested via `-kind` |
| `codelens` | `-exec` (boolean) — run the first matching lens instead of only listing | Takes `<file>`, `<file:line>`, or `<file> <title>` as positional args |
| `execute` | none beyond the shared write flags | Takes `<command> <json-argument>` — sends a raw LSP `ExecuteCommand` request; gopls's command set (`command.Interface`) is unstable and may change between versions |
```bash
# List available code actions for a range
gopls codeaction -kind=quickfix ./gopls/main.go
# Execute the first matching action and show a diff
gopls codeaction -kind=quickfix -exec -diff ./gopls/main.go
# Filter by title (regex) in addition to kind
gopls codeaction -kind=refactor.rewrite -title 'Fill struct' -exec -w file.go:12:3
# Code lenses: list, or run a specific one
gopls codelens a_test.go # list lenses in a file
gopls codelens a_test.go:10 # list lenses on line 10
gopls codelens a_test.go "run test" # list gopls.run_tests commands
gopls codelens -exec a_test.go:10 "run test" # run a specific test
# Execute a raw LSP ExecuteCommand
gopls execute gopls.add_import '{"ImportPath": "fmt", "URI": "file:///hello.go"}'
gopls execute gopls.run_tests '{"URI": "file:///a_test.go", "Tests": ["Test"]}'
gopls execute gopls.list_known_packages '{"URI": "file:///hello.go"}'
```
## Introspection
| Command | Flags | Notes |
| --- | --- | --- |
| `stats` | `-anon` (boolean) | JSON summary of workspace info relevant to performance; populates the file cache as a side effect. `-anon` redacts fields that could leak user/file names or source text |
| `version` | none | Print gopls version info |
| `api-json` | none | Print gopls' full API surface as JSON |
| `bug` | none | Report a bug in gopls |
| `licenses` | none | Print licenses of bundled software |
```bash
gopls stats
gopls stats -anon
gopls version
gopls api-json
gopls bug
gopls licenses
```
## CodeAction kind reference
Passed to `-kind` on `codeaction` (comma-separated, hierarchical — `refactor` matches all `refactor.*`):
```
gopls.doc.features
quickfix
refactor
refactor.extract
refactor.extract.constant
refactor.extract.function
refactor.extract.method
refactor.extract.toNewFile
refactor.extract.variable
refactor.inline
refactor.inline.call
refactor.rewrite
refactor.rewrite.changeQuote
refactor.rewrite.fillStruct
refactor.rewrite.fillSwitch
refactor.rewrite.invertIf
refactor.rewrite.joinLines
refactor.rewrite.removeUnusedParam
refactor.rewrite.splitLines
source
source.assembly
source.doc
source.fixAll
source.freesymbols
source.organizeImports
source.test
```
A few additional kinds exist beyond this `-kind`-documented set but are reachable only through editor UI or `execute`/code lens, not by name filter: `refactor.extract.variable-all`, `refactor.extract.constant-all`, `refactor.inline.variable`, `refactor.rewrite.moveParamLeft`, `refactor.rewrite.moveParamRight`, `refactor.rewrite.eliminateDotImport`, `refactor.rewrite.addTags`, `refactor.rewrite.removeTags`, `refactor.rewrite.implementInterface`, `source.addTest`, `source.splitPackage`, `source.toggleCompilerOptDetails`. See [features.md](features.md#transformation) for what each one does.
references/features.md
# gopls feature catalog
Source: [tip.golang.org/gopls/features](https://tip.golang.org/gopls/features/). Each entry names the LSP request or `CodeAction` kind so a specific behavior can be looked up in the upstream docs by exact term.
## Table of contents
- [Navigation](#navigation)
- [Passive (always-on)](#passive-always-on)
- [Diagnostics](#diagnostics)
- [Transformation](#transformation)
- [Web-based features](#web-based-features)
- [Non-Go files](#non-go-files)
- [Completion](#completion)
## Navigation
**Definition** (`textDocument/definition`, CLI `gopls definition`) — jumps to a symbol's declaration. Handles more than plain identifiers: on an import path it lists the imported package's declarations; on a `go:linkname` directive it finds the linked symbol; on a `go:embed` pattern it finds the embedded file; on a doc-comment link it follows the reference; on a non-Go function it can return the assembly implementation; on `return` it locates the named result variables; on `goto`/`break`/`continue` it finds the target label or block. Already at the declaration → most clients reinterpret the request as "find references" instead.
**Type Definition** (`textDocument/typeDefinition`, no CLI equivalent) — jumps to the _named type_ underlying a symbol, unwrapping pointer, array, slice, channel, and map constructors first. For `x chan []*T`, this reports the definition of `T`; it works only on symbols, not arbitrary expressions. No agent-invocable path: it is absent from the native `LSP` tool's fixed operation list (`goToDefinition`, `findReferences`, `hover`, `documentSymbol`, `workspaceSymbol`, `goToImplementation`, call hierarchy), so only a full editor LSP client can reach it.
**References** (`textDocument/references`, CLI `gopls references`) — lists every use of a symbol: for an interface method, this includes concrete implementations; for a package declaration, it includes both direct imports and other files' package clauses; for an embedded field, it reports only field references (use Type Definition to find references to the type itself). **Scoping gotcha:** results reflect only the build configuration of the queried file — a query issued against `foo_windows.go` will not surface a match in `bar_linux.go`. Built-in symbols (`int`, `append`) are rejected as too numerous to be useful.
**Implementation** (`textDocument/implementation`, CLI `gopls implementation`) — on an interface, returns concrete implementations and sub-interfaces; on a concrete type, returns interfaces it satisfies; on an interface method, returns the concrete methods satisfying it, and vice versa. Matching uses method sets for types and signatures for functions, with generic types treated as wildcards — a candidate is included if _any_ instantiation would allow one to implement the other, without full unification checking. LSP's built-in bias toward subtypes makes this query directionally asymmetric — for full bidirectional traversal, use Type Hierarchy instead.
**Document Symbol** (`textDocument/documentSymbol`, CLI `gopls symbols`) — outline of a single file's top-level declarations. File-scoped; use Symbol for cross-file search.
**Symbol / Workspace Symbol** (`workspace/symbol`, CLI `gopls workspace_symbol`) — fuzzy search across the whole workspace. Default matcher is `fastFuzzy` (FZF-inspired), so abbreviations and typos still match — `DocSym` matches `DocumentSymbol`. Controlled by the `symbolMatcher`, `symbolStyle`, and `symbolScope` settings (see [settings.md](settings.md)); `directoryFilters` excludes directories from the search.
**Selection Range** (`textDocument/selectionRange`, no CLI equivalent) — expands or contracts the current selection along syntactic boundaries (expression → statement → block → function). Useful for selecting exactly the region an Extract refactor needs.
**Call Hierarchy** (`textDocument/prepareCallHierarchy` + `callHierarchyItem/incomingCalls`/`outgoingCalls`, CLI `gopls call_hierarchy`) — shows a function's callers and callees as a static graph. **Only static calls are included** — calls made through a function value or an interface method are invisible, since detecting them isn't analytically tractable. Invoke on the function declaration's name, and corroborate with References when a dynamically-dispatched call site matters.
**Type Hierarchy** (`textDocument/prepareTypeHierarchy` + `typeHierarchyItem/subtypes`/`typeHierarchy/supertypes`, no CLI equivalent yet) — bidirectional view of the subtyping relation: which types implement an interface, and which interfaces a type satisfies. Resolves the asymmetry Implementation has. Limited to **named types** (unlike Implementation, which also matches unnamed function types); alias types are excluded; function-local types are visible only within the same package.
## Passive (always-on)
These need no explicit invocation — they fire continuously as an editor session progresses. Most degrade if the surrounding package has build errors, since they depend on successful type-checking.
**Hover** (`textDocument/hover`) — symbol name/kind/type/value, doc comment (with clickable doc links like `[fmt.Printf]`), promoted methods from embedded fields, struct field size/offset and wasted-space percentage (flagged at ≥20% waste), expanded `//go:embed` patterns, `//go:linkname` targets, and which Go release introduced a given stdlib symbol. Controlled by `hoverKind` (verbosity) and `linkTarget` (base URI for doc links).
**Signature Help** (`textDocument/signatureHelp`) — parameter names/types/docs for the function being called, with the active parameter highlighted; works even while the cursor sits inside the function name, not just inside the parens.
**Document Highlight** (`textDocument/documentHighlight`) — highlights every identifier referring to the same symbol in view, plus related tokens: named results and their return statements, loop control keywords (`for`/`break`/`continue`), switch tokens, a function and its own return statements. Read vs. write references are typically color-coded differently by the client.
**Inlay Hint** (`textDocument/inlayHint`) — inline annotations, off by default (visual clutter), toggled per-kind via the `hints` setting: `parameterNames` (call-site argument labels), `assignVariableTypes`, `compositeLiteralFields`, `compositeLiteralTypes`, `constantValues` (including computed `iota` values), `functionTypeParameters` (generic instantiations), `rangeVariableTypes`.
**Semantic Tokens** (`textDocument/semanticTokens`) — richer syntax coloring than naive lexing: token types (`function`, `keyword`, `macro`, `method`, `namespace`, `number`, `operator`, `parameter`, `string`, `type`, `typeParameter`, `variable`, …) plus modifiers including a custom `shadowing` modifier that flags shadowed declarations. Off by default due to type-checking latency (`semanticTokens` setting); `noSemanticString`/`noSemanticNumber` let a client opt out of just those two kinds if it prefers its own lexical highlighting for them.
**Folding Range** (`textDocument/foldingRange`) — collapsible regions for large comments, functions, and blocks.
**Document Link** (`textDocument/documentLink`) — turns URLs in doc comments and import declarations into clickable links (imports link to their pkg.go.dev page). Controlled by `importShortcut` and `linkTarget`.
## Diagnostics
Three sources, distinguished by the LSP diagnostic's `source` field:
1. **Compilation errors** — gopls doesn't invoke the real compiler; it runs `go list` for package metadata (`source: "go list"`) then mimics the compiler front-end itself: read, scan, parse, type-check (`source: "compiler"`).
2. **Analysis findings** — the `go vet` analysis framework plus gopls's own analyzers, each reporting under its own analyzer name as `source`. The `printf` analyzer (format-string/argument mismatches) is a representative example.
3. **Compiler optimization details** — off by default; toggled per-package with the `source.toggleCompilerOptDetails` code action. Surfaces escape-analysis results, nil-check elimination, and inlining decisions. Only available on packages that are otherwise error-free.
**Recomputation timing:** open-file compile errors update within tens of milliseconds of a keystroke. Workspace-wide analysis diagnostics recompute after roughly a second of idle time, tunable via `diagnosticsDelay`; `diagnosticsTrigger` can switch this to save-triggered instead of edit-triggered. Clients can also request diagnostics explicitly (`textDocument/diagnostic`, "pull diagnostics") if initialized with `pullDiagnostics: true` — off by default for performance.
**Notable quick fixes**, offered as code actions attached to a diagnostic:
- `fillreturns` — heuristically completes an incomplete `return` statement.
- `stubMissingInterfaceMethods` — generates stub methods when a concrete type doesn't yet satisfy a required interface.
- `StubMissingCalledFunction` — creates a stub for an undefined function/method, inferring its signature from the call site.
- `CreateUndeclared` — declares a missing variable or function based on how it's used.
- Fixes marked `source.fixAll` are considered unconditionally safe; most editors offer a single shortcut to apply all of them at once.
CLI: `gopls check <file>` (`-severity=hint|info|warning|error`, default `warning`).
## Transformation
Three underlying mechanisms: **Formatting** and **Rename** are primary LSP requests; most everything else is a **CodeAction** (requested per-range, returns either a direct edit or a lazily-computed command); a handful of dependency-management actions are **CodeLenses** instead.
**Formatting** (`textDocument/formatting`, CLI `gopls format`) — canonical Go formatting; client-supplied formatting options are ignored. `gofumpt: true` switches to `mvdan.cc/gofumpt`'s stricter rules.
**Organize Imports** (`source.organizeImports`, CLI `gopls imports`) — removes unused/duplicate imports, adds missing ones (via workspace-wide heuristics — occasionally surprising), sorts them. The `local` setting groups a path prefix as "local," matching `goimports -local`. Most editors run this on save; disable per-language if that's unwanted.
**Rename** (`textDocument/rename`, CLI `gopls rename`) — two-stage: `prepareRename` reports the current name, then `rename` applies the change everywhere. Refuses renames that would introduce shadowing or break interface satisfaction. Special positions unlock extra behavior:
- Rename a **method's receiver declaration** → renames the receiver identifier across every method of that type; rename a receiver **use** → renames only that one variable.
- Rename the **package name in a `package` clause** → moves every file in the package to a new directory (subpackages stay put unless `renameMovesSubpackages` is set); refused across module boundaries or into an existing package.
- Rename the **`func` keyword** of a declaration → lets you edit the whole signature; parameter/result count and types must stay the same (no adding/removing parameters this way — see `refactor.rewrite.removeUnusedParam`/`moveParamLeft`/`moveParamRight` for that).
**Extract** (`refactor.extract.*`) — replaces a selection with a reference to a new declaration:
- `refactor.extract.variable` / `.constant` — one new local binding for the selected expression, plus `-all` variants that rewrite every occurrence within the enclosing function.
- `refactor.extract.function` / `.method` — turns one or more complete statements into a call to a new function (or method, on the same receiver, if extracted inside a method).
- `refactor.extract.toNewFile` (gopls ≥ v0.17.0) — moves selected top-level declarations into a new file, adding imports as needed; the new filename derives from the first declared symbol.
Extract is less rigorous than Rename/Inline: comments are sometimes dropped, and files carrying a `DO NOT EDIT` generated-code marker receive no code actions at all.
**Inline** (`refactor.inline.*`):
- `refactor.inline.call` — replaces a call with the function body, substituting parameters for arguments. Works only for static calls to accessible functions/methods (not through a function value or interface method, not to unexported names outside the package, not into `internal` packages, not for generic functions). Preserves side-effect ordering (introduces `var`s when an argument must not be duplicated or reordered), keeps qualified references correct (`Printf` → `fmt.Printf` with the import added), keeps implicit conversions explicit, and never drops a variable's last use. `defer` bodies stay wrapped in a closure since defer semantics are tied to function boundaries.
- `refactor.inline.variable` — replaces a local variable's use with its initializer expression; refuses if an identifier in that initializer has been shadowed since the declaration.
**Miscellaneous rewrites** (`refactor.rewrite.*`):
- `removeUnusedParam` — the `unusedparams` analyzer offers renaming to `_` (trivial) or a full signature change that also updates every caller, preserving side-effecting arguments.
- `moveParamLeft` / `moveParamRight` — reorders one parameter, updating every call site.
- `changeQuote` — toggles a string literal between raw (`` `...` ``) and interpreted (`"..."`) form; idempotent to apply twice.
- `invertIf` — negates a plain `if`/`else` condition (no `else if` chain) and swaps the two blocks.
- `splitLines` / `joinLines` — expands or collapses a bracketed list (composite literal, call arguments, signature) one item per line; skipped for lists that already contain `//` comments or have fewer than two items.
- `fillStruct` — populates missing struct-literal fields, matching field names to in-scope variables/constants/functions where possible, zero value otherwise. Searches only the current file, above the cursor — run `source.organizeImports` first if the struct type was just introduced.
- `fillSwitch` — adds missing cases for an enum-like set of named constants, or for a type switch (one case per concrete type implementing the interface, plus a default that panics on an unexpected type).
- `eliminateDotImport` — removes a dot import and qualifies every reference, offered only when no name collision would result.
- `addTags` / `removeTags` — adds or removes struct field tags (e.g. `json`); interactive clients can choose the naming transform (`camelCase`, `snake_case`, `lisp-case`, `PascalCase`, `Title Case`).
- `implementInterface` — adds placeholder method declarations so a named type satisfies a chosen interface (defaults to `error`); interactive-dialog only, gopls-specific.
**Add Test For Function** (`source.addTest`) — generates a table-driven test for the selected function/method, creating the `_test.go` file if needed (copying copyright/build-constraint comments), using an external `p_test` package to encourage testing exported API only, naming results `got`/`got2`/…, comparing against `want`/`want2`/…, and adding a `wantErr bool` field when the final result is `error`. For a method, searches the package for a constructor (preferring `NewT` for type `T`). A leading `context.Context` parameter gets `t.Context()` on Go 1.24+, `context.Background()` otherwise.
## Web-based features
gopls runs a small localhost web server (LSP `window/showDocument`) for reports too rich for inline editor UI. Every endpoint URL embeds a random auth token; restarting gopls invalidates old links and shows a disconnected banner on any page still open.
- **Package Documentation** (`source.doc`) — a pkgsite-style rendered view of a package's docs, including **internal, unpublished packages** pkg.go.dev never sees. Symbol links jump the editor to the source declaration; reload without saving to see current edits reflected.
- **Free Symbols** (`source.freesymbols`) — lists the symbols a selection references but doesn't define itself, grouped as imported (with doc links), local, or package-level — the exact input list an Extract Function/Method refactor would need.
- **Assembly** (`source.assembly`) — the compiled assembly listing for a function, source-line-linked, recompiled on each reload. Architecture follows the file's build tags (e.g. `foo_amd64.go`). Not yet supported for generic functions, `func init`, or functions in test packages.
- **Split Package** (`source.splitPackage`) — an interactive dependency-graph tool for planning how to break a package into smaller, acyclic components. It visualizes the split but does not yet perform the actual code movement/renaming.
All of these send edits/navigation back to the editor via `showDocument`, which works even against modified-but-unsaved source.
## Non-Go files
**Templates** (`text/template`/`html/template`) — disabled until `templateExtensions` lists at least one extension (templates have no canonical extension of their own); the editor also needs to associate that extension with the `tmpl`/`gotmpl` language ID (e.g. VS Code's `files.associations`). Inside `{{ }}` delimiters: diagnostics (parse errors; missing functions are not flagged), full syntax highlighting, definitions and references (all templates share one global scope), and completions. Hover, semantic tokens, symbol search, and document highlight are not yet implemented, and custom delimiters other than `{{`/`}}` are not understood.
**go.mod / go.work** — hover, hints, vulncheck-driven diagnostics, and code lenses (add dependency, upgrade dependency, tidy, run `govulncheck`) are supported; the upstream page marks the fine-grained behavior of each as still under documentation, so verify current behavior directly against a `go.mod` file in an editor session rather than relying on an exhaustive list here.
**Assembly (`.s`) files** — basic support exists; treat as best-effort.
## Completion
Upstream documentation for this feature is a stub as of this writing (tracked as [golang/go#62022](https://github.com/golang/go/issues/62022)) — rely on empirical behavior plus these known settings rather than a documented spec: `usePlaceholders` (fills in placeholder parameter names on completion), `completeFunctionCalls` (adds trailing parentheses, on by default), `completeUnimported` and `matcher`/`deepCompletion`-style settings shape whether not-yet-imported packages and nested field/method completions are offered. See [settings.md](settings.md) for the full settings surface.
references/matrix.md
# Capability → CLI → MCP → native LSP
Every gopls capability, mapped to its CLI command, MCP tool, and native `LSP` tool operation where one exists. `—` means that surface has no path to this capability.
| Capability | CLI | MCP tool | Native LSP op |
| --- | --- | --- | --- |
| Workspace layout (module/workspace/GOPATH) | `gopls stats` | `go_workspace` | — |
| Fuzzy-find a symbol by name, workspace-wide | `gopls workspace_symbol <query>` | `go_search` | `workspaceSymbol` |
| Go to definition | `gopls definition f:l:c` | — (use `go_file_context`/`go_package_api`) | `goToDefinition` |
| Go to type definition | — (unsupported) | — | — (not in the native tool's fixed op list) |
| Find all references | `gopls references f:l:c` | `go_symbol_references` | `findReferences` |
| Implements / implemented-by | `gopls implementation f:l:c` | — | `goToImplementation` |
| Full subtype/supertype tree | — (not yet supported) | — | Type Hierarchy |
| Call graph (callers/callees) | `gopls call_hierarchy f:l:c` | — | Call Hierarchy |
| Expand/contract selection along syntax boundaries | — (unsupported) | — | `selectionRange` (editor gesture, no agent-invoked path) |
| File's own symbols (outline) | `gopls symbols <file>` | `go_file_context` | `documentSymbol` |
| A package's public API | — | `go_package_api` | (hover per-symbol) |
| A file's intra-package dependencies | — | `go_file_context` | — |
| Hover info (type, doc, size/offset) | — | — | `hover` |
| Signature help | `gopls signature f:l:c` | — | signature help |
| Same-symbol identifier highlights | `gopls highlight f:l:c` | — | `documentHighlight` (not in the native tool's fixed op list) |
| Semantic tokens (rich syntax coloring) | `gopls semtok <file>` | — | `semanticTokens` (editor-automatic, not agent-invoked) |
| Folding ranges (collapsible regions) | `gopls folding_ranges <file>` | — | `foldingRange` (editor-automatic, not agent-invoked) |
| Document links (URLs in doc comments/imports) | `gopls links <file>` | — | `documentLink` (editor-automatic, not agent-invoked) |
| Compiler + analyzer diagnostics | `gopls check <file>` | `go_diagnostics` | automatic, pushed after every edit |
| Vulnerability reachability (current build) | — | `go_vulncheck` | — |
| Safe rename (symbol, receiver, package move, signature) | `gopls rename -w f:l:c NewName` | `go_rename_symbol` | rename |
| Organize / fix imports | `gopls imports -w <file>` | — | `source.organizeImports` code action |
| Format | `gopls format -w <file>` | — | `textDocument/formatting` |
| Refactor (extract, inline, fill, rewrite — see [features.md](features.md)) | `gopls codeaction -kind=<kind> -exec -w <file>` | — | code action |
| Generate a test for a function | `gopls codelens -exec <file:line> "..."` (via `source.addTest`) | — | code action / code lens |
| Rendered package documentation (incl. internal packages) | — | — | `source.doc` code action → browser report |
| Free symbols of a selection (inputs before extracting) | — | — | `source.freesymbols` code action → browser report |
| Assembly listing for a function | — | — | `source.assembly` code action → browser report |
| Split-package dependency planning | — | — | `source.splitPackage` code action → browser report |
references/mcp.md
# gopls MCP server & native `LSP` tool reference
## Table of contents
- [Starting the server](#starting-the-server)
- [Registering the MCP server](#registering-the-mcp-server)
- [MCP tools](#mcp-tools)
- [The native `LSP` tool](#the-native-lsp-tool)
- [What the MCP server can and cannot do](#what-the-mcp-server-can-and-cannot-do)
## Starting the server
A standalone gopls instance speaking MCP over stdin/stdout, launched fresh per session, no LSP client involved:
```bash
gopls mcp
```
Only sees files as they exist **on disk** — an edit made through a different tool but not yet saved is invisible to it. This is the right mode for an agent-only workflow with no attached editor.
## Registering the MCP server
The underlying command that starts the server (`gopls mcp`) is harness-agnostic — any MCP-capable host can point at it. Claude Code registers it via its own CLI:
```bash
claude mcp add gopls -- gopls mcp
```
Other MCP-capable harnesses (Cursor, Windsurf, and others) each have their own MCP server registration — an entry in their respective settings file pointing at `gopls mcp` as the launch command, not a shared config format.
## MCP tools
Eight tools, all keyed by name/path/query rather than cursor position — this is the main ergonomic difference from the native `LSP` tool.
| Tool | Purpose | Example |
| --- | --- | --- |
| `go_workspace` | Learn the workspace's overall structure — module, multi-module workspace, or GOPATH project. Call this first, once per session. | `go_workspace({})` |
| `go_vulncheck` | On-demand reachability check: which known vulnerabilities does the _current_ build actually reach. Run right after `go_workspace` if in a Go workspace, and again after any `go.mod` change. | `go_vulncheck({"pattern":"./..."})` |
| `go_search` | Fuzzy search for a type, function, or variable by name across the workspace — use when you don't know the exact location. | `go_search({"query":"server"})` |
| `go_file_context` | Summarize a file's dependencies on other files in the _same package_. Run this immediately after reading any Go file for the first time. | `go_file_context({"file":"/path/to/server.go"})` |
| `go_package_api` | Show a package's public API — most valuable for third-party dependencies or sibling packages in a monorepo you haven't read file-by-file. | `go_package_api({"packagePaths":["example.com/internal/storage"]})` |
| `go_symbol_references` | Find every reference to a symbol — run before modifying any definition to gauge the blast radius. | `go_symbol_references({"file":"/path/to/server.go","symbol":"Server.Run"})` |
| `go_diagnostics` | Build/analysis errors for the given files — mandatory after every edit. | `go_diagnostics({"files":["/path/to/server.go"]})` |
| `go_rename_symbol` | Rename a symbol and every reference to it, workspace-wide, with the same safety checks as LSP rename (blocks changes that would break interface satisfaction). | — |
See [SKILL.md](../SKILL.md#efficient-workflows) for the Read/Edit workflow order these tools are designed to be chained in.
## The native `LSP` tool
Claude Code's built-in editor-style integration — a different mechanism from the MCP server above, worth wiring in addition to it, not instead of it.
**Enabling it:**
1. Set the environment variable `ENABLE_LSP_TOOL=1` (off by default).
2. Install `gopls` (`go install golang.org/x/tools/gopls@latest`).
3. Install the official `gopls-lsp@claude-plugins-official` marketplace plugin to wire `gopls` as the Go language server backing the tool.
**Operations**, all keyed by `line`/`character` rather than name/path:
- `goToDefinition`
- `findReferences`
- `hover`
- `documentSymbol`
- `workspaceSymbol`
- `goToImplementation`
- call hierarchy
`goToTypeDefinition` is intentionally absent from this list — the native tool does not expose it, so type-definition navigation has no agent-invocable path (see [features.md](features.md#navigation)).
Because these need a location up front, they're most efficient once you already have one — right after a grep or a file read — rather than as the first move in an investigation (that's what `go_search` on the MCP server is for).
**Its unique value:** compiler diagnostics are pushed into context **automatically after every edit**, with no explicit diagnostics call needed — the MCP server's `go_diagnostics` requires an explicit invocation each time.
## What the MCP server can and cannot do
The gopls MCP server wraps LSP functionality with these boundaries:
- **Can**: read files from the filesystem and return their contents; execute `go` commands to load package metadata (which may reach `proxy.golang.org` and write to the local Go module/build cache); write to gopls's own cache/configuration files; upload telemetry if the user has opted in.
- **Cannot**: make arbitrary writes to the source tree outside of the edits a tool call explicitly returns; make arbitrary network requests beyond what `go` itself needs to resolve the build.
Either mode — MCP or native `LSP` — only ever reasons about code that is present and resolvable in the local build: the workspace plus every dependency exactly as pinned in `go.sum`, including `replace` directives. For anything outside that boundary, → See `samber/cc-skills-golang@golang-pkg-go-dev` skill (`godig`).
references/settings.md
# gopls settings reference
Source: [tip.golang.org/gopls/settings](https://tip.golang.org/gopls/settings); full canonical list: `gopls api-json`. Settings are passed via the LSP client's `initializationOptions` (editor-specific config file/UI) — there is no `gopls.json` read from the workspace by default. Record the chosen settings in the project's agent-config file (CLAUDE.md, AGENTS.md, or equivalent), so future sessions pick them up without rediscovering them.
## Table of contents
- [Build](#build)
- [Formatting](#formatting)
- [Diagnostics](#diagnostics)
- [Documentation](#documentation)
- [Inlay hints](#inlay-hints)
- [Navigation](#navigation)
## Build
| Setting | Type | Default | Purpose |
| --- | --- | --- | --- |
| `buildFlags` | `[]string` | `[]` | Extra flags for the build system, most commonly `-tags=<tag>` to bring build-tagged files into scope |
| `env` | `map[string]string` | `{}` | Environment variables for external commands gopls shells out to (`go list`, etc.) |
| `directoryFilters` | `[]string` | `["-**/node_modules"]` | Include/exclude workspace directories from loading and from workspace-symbol search, using `+`/`-` prefixed glob patterns |
| `expandWorkspaceToModule` | `bool` | `true` | Whether the enclosing module (not just the opened directory) counts as "workspace" for diagnostics scope |
| `templateExtensions` | `[]string` | `[]` | File extensions treated as Go template files (templates have no canonical extension, so this is empty by default) |
**When it matters:** a symbol behind a build tag (`//go:build integration`) is invisible to `references`/`go_search` until `buildFlags: ["-tags=integration"]` is set — this is the same root cause as the References build-configuration scoping gotcha in [features.md](features.md#navigation).
## Formatting
| Setting | Type | Default | Purpose |
| --- | --- | --- | --- |
| `local` | `string` | `""` | Import path prefix treated as "local" for import grouping/sort order — equivalent to `goimports -local` |
| `gofumpt` | `bool` | `false` | Format with `mvdan.cc/gofumpt`'s stricter ruleset instead of plain `gofmt` |
## Diagnostics
| Setting | Type | Default | Purpose |
| --- | --- | --- | --- |
| `analyses` | `map[string]bool` | `{}` | Enable/disable individual analyzers by name (the `go vet`-based framework plus gopls's own) |
| `staticcheck` | `bool` | `false` | Enable the staticcheck.io analyzer suite in addition to the built-in analyzers |
| `vulncheck` | enum: `Off`\|`Imports`\|`Prompt` | `"Prompt"` (or `"Off"` in some client defaults) | Whether/how vulnerability-driven diagnostics on `go.mod` run |
| `diagnosticsDelay` | `time.Duration` | `"1s"` | Idle time after an edit before workspace-wide analysis diagnostics recompute (open-file compile errors update sooner regardless) |
| `diagnosticsTrigger` | enum: `Edit`\|`Save` | `"Edit"` | Whether diagnostics recompute on every edit or only on save |
| `pullDiagnostics` | `bool` | `false` | Let the client request diagnostics on demand (`textDocument/diagnostic`) instead of only receiving pushed updates |
**When it matters:** a large monorepo with `diagnosticsTrigger: "Edit"` (the default) can feel laggy under `diagnosticsDelay: "1s"` on every keystroke pause — switching to `"Save"` trades immediacy for fewer full-workspace recomputations. Turning on `staticcheck` surfaces a materially different (larger) set of findings than the default analyzer set — expect more `go_diagnostics`/`gopls check` output afterward, not a regression.
## Documentation
| Setting | Type | Default | Purpose |
| --- | --- | --- | --- |
| `hoverKind` | enum: `FullDocumentation`\|`SingleLine`\|`Structured`\|`NoDocumentation`\|`SynopsisDocumentation` | `"FullDocumentation"` | How much doc text Hover renders |
| `linksInHover` | `bool` | `true` | Whether hover markdown includes doc-comment links |
| `linkTarget` | `string` | `"pkg.go.dev"` | Base host used when generating documentation links (hover, Document Link, diagnostics) |
## Inlay hints
| Setting | Type | Default | Purpose |
| --- | --- | --- | --- |
| `hints` | `map[string]bool` | `{}` (all off) | Enables specific inlay hint kinds — keys are `parameterNames`, `assignVariableTypes`, `compositeLiteralFields`, `compositeLiteralTypes`, `constantValues`, `functionTypeParameters`, `rangeVariableTypes` |
Example:
```json
"hints": {
"parameterNames": true,
"assignVariableTypes": true
}
```
## Navigation
| Setting | Type | Default | Purpose |
| --- | --- | --- | --- |
| `symbolMatcher` | enum: `FastFuzzy`\|`Fuzzy`\|`CaseSensitive`\|`CaseInsensitive` | `"FastFuzzy"` | Matching algorithm for `workspace/symbol` / `go_search` |
| `symbolScope` | enum: `all`\|`workspace` | `"all"` | Whether symbol search covers only workspace packages or every loaded package (including dependencies) |
| `symbolStyle` | enum | — | How matched symbols are qualified in the response (package-qualified vs. bare) |
| `codelenses` | `map[string]bool` | — | Enables/disables individual code lenses (e.g. `generate`, `tidy`, `vendor`, `run_tests`) |
---
For the complete, always-current settings surface (including experimental and client-specific keys), see `gopls api-json` or the upstream settings page linked above — this table covers the settings most likely to change how navigation, diagnostics, or refactors behave day-to-day, not the full API.
SKILL.md
---
name: golang-gopls
description: "Golang semantic code intelligence via `gopls`, the official Go language server — go-to-definition, find references, call/implementation hierarchy, workspace symbol search, package API discovery, diagnostics, safe rename, refactors (extract/inline/fill/rewrite code actions), formatting, and generated tests. Reaches an agent via gopls's own MCP server (`go_*` tools), Claude Code's native `LSP` tool, or the `gopls` CLI. Use when navigating or refactoring Go code — jumping to a definition, finding call sites before a rename, understanding a file's or package's dependencies, running diagnostics after an edit, or extracting/inlining/renaming. Not for the published ecosystem — packages not in your `go.mod`, versions, licenses, importers — → See `samber/cc-skills-golang@golang-pkg-go-dev` skill (`godig`). Not for a whole-tree vulnerability audit → See `samber/cc-skills-golang@golang-security` skill (`govulncheck`)."
user-invocable: true
license: MIT
compatibility: Designed for Claude Code, Codex or similar harness. Requires the gopls binary (go install golang.org/x/tools/gopls@latest) v0.20+ on PATH.
metadata:
author: samber
version: "1.1.1"
openclaw:
emoji: "🛰️"
homepage: https://github.com/samber/cc-skills-golang
requires:
bins:
- go
- gopls
install:
- kind: go
package: golang.org/x/tools/gopls@latest
bins: [gopls]
skill-library-version: "0.22.0"
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*) Bash(git:*) Agent Bash(gopls:*) LSP mcp__gopls__*
paths:
- "**/*.go"
---
**Persona:** You are a Go engineer who reaches for semantic code intelligence instead of grep whenever a question is about the resolved build — grep finds text, `gopls` finds meaning (types, call graphs, shadowing, implementation relationships).
**Dependencies:** `gopls` — `go install golang.org/x/tools/gopls@latest` (v0.20+). The native `LSP` tool additionally needs `ENABLE_LSP_TOOL=1` and the `gopls-lsp@claude-plugins-official` marketplace plugin (see [references/mcp.md](references/mcp.md)).
`gopls` is the official Go language server. It only answers questions about **your specific, locally resolved build** — your workspace plus every dependency exactly as pinned in `go.sum`, including `replace` directives. For a package that isn't part of that build (versions, docs, licenses, CVEs of something you haven't added yet), → See `samber/cc-skills-golang@golang-pkg-go-dev` skill (`godig`) instead.
## Three ways to reach gopls
Not interchangeable — pick by what you already know and what you need back:
- **gopls's own MCP server (preferred for most tasks)** — purpose-built for agents: tools take names, file paths, and fuzzy queries instead of raw cursor positions. Register once per machine: `claude mcp add gopls -- gopls mcp`. Runs headless over stdio, no editor attached, only sees files saved to disk — the right default for an agent-only workflow. See [references/mcp.md](references/mcp.md) for every tool.
- **The native `LSP` tool** — Claude Code's built-in editor-style integration. Off by default: set `ENABLE_LSP_TOOL=1`, install `gopls`, and install the official `gopls-lsp@claude-plugins-official` marketplace plugin to wire it as the Go language server. Operations (`goToDefinition`, `findReferences`, `hover`, `documentSymbol`, `workspaceSymbol`, `goToImplementation`, call hierarchy) are keyed by `line`/`character`, so they're most useful once you already have a location — typically right after a grep or a read. Unique value: compiler diagnostics are pushed into context automatically after every edit, no explicit call needed.
- **The `gopls` CLI** — same engine, invoked as `gopls <command> <file:line:col>`. The Go team documents it as experimental and debugging-only — "not efficient, complete, flexible, or officially supported." Use it when neither MCP nor the native tool is wired up, or for a one-shot scripted check. Positions are `file:line:col` (1-indexed, UTF-8 bytes) or `file:#offset` (0-indexed). See [references/cli.md](references/cli.md).
**Preference order: MCP → native `LSP` → CLI.** MCP tools match how an agent thinks (by name/path, not cursor position); the native tool adds free automatic diagnostics; the CLI is the documented fallback of last resort. Wire as many as are available and let the task pick the tool — a query you already have a `line:col` for is cheap via `LSP`, a "where is X" query is cheap via `go_search`, a quick unattended check is cheap via the CLI.
## Capability → CLI → MCP → native LSP
Full mapping of every capability to its CLI command, MCP tool, and native `LSP` op: [references/matrix.md](references/matrix.md).
## Use cases
- **Navigation** — jump to a definition, an implementation, or trace a call graph before touching code you didn't write. Details: [references/features.md](references/features.md#navigation).
- **Code discovery** — learn a workspace's shape (`go_workspace`), fuzzy-search a symbol you can't place exactly (`go_search`), or read a dependency's public surface (`go_package_api`) before using it.
- **Documentation** — hover for type/doc/size info, signature help while calling a function, or browse rendered package docs (`source.doc`, including internal packages pkg.go.dev never sees).
- **Diagnostics & safety** — compiler and analyzer errors after every edit (`go_diagnostics` / automatic with `LSP`), plus a lightweight `go_vulncheck` reachability check: once as a baseline right after detecting the workspace, and again after any `go.mod` change.
- **Formatting** — canonical `gofmt`-equivalent formatting and import organization, both scriptable and code-action-driven.
- **Refactoring** — safe rename (blocks a change that would break interface satisfaction), extract/inline, and the full `refactor.rewrite.*` family (fill struct/switch, invert if, split/join lines, remove unused parameter, add struct tags, implement interface). Full catalog with gotchas: [references/features.md](references/features.md#transformation).
## Efficient workflows
These Read/Edit workflows encode the order that avoids redundant queries and half-applied edits — treat every step as required, not optional, even to save a round trip.
- **Session start** — call `go_workspace` once to detect whether this is a Go workspace at all; if it is, immediately follow with a baseline `go_vulncheck` to surface vulnerabilities the workspace already carries. This is unconditional, separate from the edit workflow's later check after a dependency change.
**Read workflow** (understand before touching anything):
1. `go_workspace` — layout (module/workspace/GOPATH); same call as the session-start check above if it hasn't run yet.
2. `go_search` — fuzzy-locate a type/function/variable by name.
3. `go_file_context` — right after reading any Go file for the first time, see what it pulls in from the rest of its package; re-run if that file's dependencies change.
4. `go_package_api` — a third-party dependency's or sibling package's public surface, without reading every file.
**Edit workflow** (iterate until diagnostics are clean):
1. Read first (workflow above).
2. `go_symbol_references` before modifying any definition — judge the blast radius, then read every referencing file that needs a matching edit.
3. Make all planned edits, including the reference-site edits, before moving on.
4. `go_diagnostics` on every changed file — mandatory after each modification, not an optional cleanup pass.
5. Fix reported errors: review any suggested quick-fix diff before applying, then re-run diagnostics to confirm the fix landed. Ignore hint/info diagnostics unrelated to the task. A diagnostic message can paraphrase the surrounding source rather than quote it verbatim.
6. Only if `go.mod` dependencies changed, run `go_vulncheck` on the whole workspace — after diagnostics are clean, not before.
7. Run `go test <changed-package-paths>` — not `./...` unless explicitly asked, since a full-repo run slows the iteration loop.
**Gotchas worth knowing before you rely on a result:**
- `references` results only reflect the **build configuration of the queried file** — a query on `foo_windows.go` will not surface matches in `bar_linux.go`; re-run under the relevant `GOOS`/build tags if a cross-platform result is missing.
- `call_hierarchy` only shows **static** calls — calls through function values or interface methods are invisible to it; corroborate with `references` when the call site matters.
- Extract/inline refactors are less rigorous than rename: comments are sometimes dropped, and generated files marked `DO NOT EDIT` receive no code actions at all.
- `refactor.rewrite.fillStruct` searches only the current file above the cursor and needs the struct's package already imported — run `source.organizeImports` first if the type was just typed in.
## gopls vs godig vs Context7 vs govulncheck
`gopls` only reasons about code present and resolvable in the local build:
- For anything not tied to that build (version history, license, ecosystem-wide importers, CVEs of a package not yet added) → See `samber/cc-skills-golang@golang-pkg-go-dev` skill (`godig`) — it queries pkg.go.dev directly, no local checkout needed.
- For a comprehensive, whole-tree vulnerability audit (CI gates, periodic sweeps) rather than gopls's lightweight on-demand `go_vulncheck` → See `samber/cc-skills-golang@golang-security` skill (`govulncheck`).
- Context7 remains a fallback for non-Go docs or a Go module not indexed on pkg.go.dev.
The full task-to-tool matrix lives in the `samber/cc-skills-golang@golang-how-to` skill's "`godig` vs gopls vs Context7 vs govulncheck" section.