Claude Code works well with Go when you give it a focused CLAUDE.md and keep the loop tight: plan, implement, run gofmt, go test, and go vet, then review the diff. It reads Go module structure cleanly, generates table-driven tests, and can refactor concurrency code, but you should verify every race and error path yourself. This guide covers a practical setup and workflow for a Go repository.
Why Claude Code fits Go
Claude Code operates in your repository, so it sees go.mod, package boundaries, and test files the same way you do. Static typing gives it fewer ambiguous changes to propose: when it changes an interface, the compiler catches the call sites. It is also good at generating table tests from existing patterns and adding context.Context through a call chain. Because Go error handling is explicit, a diff review can quickly spot missing if err != nil blocks. It is not a replacement for gofmt, go vet, or the race detector; it is a coding agent that should run those tools before you accept changes.
Project setup: a CLAUDE.md for Go
Create a CLAUDE.md file at the repository root. Claude Code reads it at startup and after permission changes. For Go, keep it short and command-focused: how to build, test, lint, and how packages are organized. Avoid prose about general programming style; give rules that change generated code: error handling, context usage, interface placement, and formatting. You can also reference the project’s go.mod module path if the agent needs to avoid import cycles.
# CLAUDE.md
## Commands
- Build: `go build ./...`
- Test: `go test ./...`
- Race: `go test -race ./...`
- Lint: `go vet ./...`
- Format: `gofmt -w .`
## Layout
- `cmd/` holds `main` packages.
- `internal/` holds private packages; do not import from `cmd`.
- `pkg/` holds public packages with stable APIs.
## Go rules
- Run `gofmt -w` before any final diff.
- Handle every error or explicitly ignore it with `_ =` and a comment.
- Pass `context.Context` as the first parameter to functions that do I/O.
- Define small interfaces where they are consumed, not next to implementations.
- Keep table tests in the same package and name subtests with `t.Run`.
This is enough for most repositories. You may add a line about go generate if your project uses it, or a rule about not changing generated files. Use this with the practical checklist in Claude Code best practices to avoid an overlong instructions file.
A practical loop for daily work
Use plan mode for non-trivial changes. Start claude, ask it to read the relevant package and tests, then propose a plan before editing. When you approve a small step, let it implement only that change. Immediately run gofmt, go test, and go vet; do not skip this because the agent claims the code compiles. Then review the diff with git diff. Small commits make it easier to see a change that accidentally alters an interface or imports an extra module.
Example prompts for common Go tasks:
- Read
internal/user/service.goand its table tests. Add aDeletemethod that takescontext.Contextand returns an error. Update the deletion tests to cover a not-found case. - Refactor
cmd/api/handlers.goto define a small interface with only the methods it uses fromUserStore, then update the fake store ininternal/testutilto implement it. - Audit every goroutine started in
internal/worker. Show a patch that useserrgroupor an explicitsync.WaitGroupwith error collection and respects context cancellation. - Run
go test -race ./...and fix the data races you find, keeping table tests readable. - Before I commit, run
gofmtandgo vet ./...; list anything that does not match the project’s existing style.
If you want a plan-first workflow, start with Claude Code plan mode and ask for a file-by-file change list before any edits.
Strengths and weak spots in Go
Claude Code is effective at several Go-specific jobs: updating table-driven tests when you add a field or case, extracting an interface from a concrete type at the call site, threading context.Context through a handler or storage layer, adding error wrapping with fmt.Errorf and %w, and fixing compiler errors across packages. It also handles repetitive renames better than global search-and-replace when package boundaries matter.
Watch closely in these areas:
- Goroutine lifecycle: generated code may launch a goroutine without a
defercleanup, ignore thectx.Done()channel, or use aWaitGroupincorrectly. Always run the race detector and manually inspect shutdown paths. - Interfaces: it can create interfaces that are too large or placed next to the implementation. Reject changes that violate accept interfaces, return structs unless the consumer clearly needs it.
- Error handling: the agent sometimes leaves
errunchecked in a new path or wraps an error that should be sent upstream untouched. Review every newif err != nil. - Imports and
go.mod: watch for newly added third-party modules that add little value or create version churn;go mod tidyshould be run after import changes. - Formatting and vet: the agent may produce a diff that is syntactically valid but not gofmt-clean. Run
gofmt -l .andgo vet ./...before accepting.
Testing and verification
Ask Claude Code to write tests in the same style as your existing table tests. For each new behavior, prefer table-driven tests with named subtests, and ask the agent to include cases for zero values, not-found errors, and context cancellation. Then verify with the actual Go tools rather than trusting the agent’s summary.
| Command | What it checks |
|---|---|
go build ./... | Compiles all packages, catching missing imports and interface mismatches. |
go test ./... | Runs existing unit and table tests. |
go test -race ./... | Detects data races in goroutine and channel code. |
go vet ./... | Catches suspicious constructs such as copied locks or bad printf verbs. |
gofmt -l . | Lists files that need formatting; use gofmt -w . to fix. |
One useful pattern is to ask the agent to first run the failing test or reproduce the bug with a new table case, show you the diff, and only then implement the fix. For concurrency work, instruct it to add a cancellation test with a short timeout and a done channel before it changes the production code.
Several agents on one Go project
AgentVera runs Claude Code and other coding agents’ real command line tools side by side, each in its own terminal panel. For Go work, the key benefit is separate git worktrees: agents can refactor different packages without overwriting each other’s files, and Git history plus generated commit messages and pull requests make merging clean. When an agent’s turn ends, automatic code review by a second model points to file:line issues, which helps catch Go concurrency or error-handling mistakes before they enter the main branch.
Wrap-up
Claude Code becomes a reliable Go pair programmer when the project instructions are explicit and the verification loop is always gofmt, go test -race, and go vet. Keep changes small, review concurrency and interface diffs manually, and use separate worktrees when running multiple agents. With that discipline, the agent handles the repetitive parts of Go development while you keep control of correctness.