Cursor Rules for Go: Packages, Errors, and Tests
A practical rule set for Go projects in Cursor, covering package boundaries, error handling, concurrency patterns, and test commands. Adapt each template to your project and record the team decisions that make them specific in fenbs.
Updated 4 min read
Cursor rules for a Go project tell the assistant which packages exist, how errors travel through the code, which concurrency patterns are approved, and how to run and write tests. Go has strong conventions in the standard library, but every project adds its own choices on top: a custom error type, a specific HTTP router, a preferred way to structure handlers. Without rules, the assistant defaults to what it has seen most often, which may not match your project. fenbs helps teams record the decisions that make their Go conventions specific, so every connected assistant starts from the agreed starting point.
The templates below are starting points. Replace the package names, import paths, and tool names with your actual project values before using them. A rule that references internal/errors only helps if that is where your error types live.
Package structure and boundaries
Go's internal/ convention gives you a way to enforce package boundaries at the compiler level, but the assistant still needs to know which internal packages exist and which ones a given context should import from. A structure rule prevents the assistant from creating new packages in the wrong place or importing across a boundary you intended to be one-directional.
Project layout: - cmd/: main packages, one per binary - internal/: private packages not importable outside this module - internal/domain: core types and interfaces, no infrastructure imports - internal/service: business logic, imports from domain only - internal/storage: database access, implements domain interfaces - internal/api: HTTP handlers, imports from service only - pkg/: reusable packages safe to import externally Do not import internal/storage from internal/service directly. Use the interfaces defined in internal/domain.
Error handling
Go error handling is idiomatic but has many valid patterns: sentinel errors, error types, wrapped errors with %w, and custom error interfaces. An assistant that switches between patterns within the same codebase makes the code inconsistent and harder to test. A rule naming your chosen approach keeps new code consistent with existing code.
Errors:
- Define error types in internal/errors/errors.go
- Wrap errors with context: fmt.Errorf("doing X: %w", err)
- Check error types with errors.Is and errors.As, not string matching
- Return errors from functions; do not panic except in main() init
- Log errors at the boundary where they leave the system (api layer)
Do not log the same error at multiple levelsConcurrency patterns
Go's goroutines and channels make concurrent code easy to write and easy to get wrong. An assistant that spawns goroutines without the project's established patterns for cancellation, error propagation, and cleanup can introduce subtle leaks. A concurrency rule names the patterns your project uses so the assistant matches them.
Concurrency: - Always accept a context.Context as the first argument in long-running functions - Use context cancellation to stop goroutines; do not rely on channel closes alone - Prefer errgroup (golang.org/x/sync/errgroup) for coordinating multiple goroutines - Never use a goroutine without a clear ownership and cleanup path - Race detector: run go test -race ./... before committing concurrent code
Testing conventions
Go's built-in testing package is minimal, and projects add their own structure: table-driven tests, testify assertions, mock generation tools, integration test tags. A rule that names your actual setup prevents the assistant from writing tests in a style that does not match the rest of the test suite.
Tests: - Use the standard testing package; add testify/assert for assertions - Write table-driven tests for functions with multiple input cases - File naming: match the source file with _test.go suffix - Tag integration tests with //go:build integration - Run unit tests: go test ./... - Run with race detector: go test -race ./... - Mocks: generate with mockery; keep generated files in mocks/
Keep your Go rule set where every assistant reads it
Add your approved Go rules to fenbs Skills and prompts alongside the decisions that shaped them. When the team adopts a new error pattern or switches mock generators, update the entry once and every connected assistant starts the next session from the current approach. fenbs does not run Go commands — it keeps the shared instructions your team has agreed on.
Create a free accountFree for one person · No credit card · Works with Claude, ChatGPT, Cursor and more
How to do this with fenbs
- Create a free account and add a project for your Go module.
- Add a skill or prompt for each rule area: package structure, error handling, concurrency, and testing. Keep each rule short — two to five specific instructions work better than a long explanation.
- Record the key team decisions in Decisions and rules: why you chose your error type approach, why the project uses or avoids a particular concurrency pattern. These give the assistant context that the rule file alone cannot provide.
- When a team member proposes changing a convention — switching from a custom error type to wrapped stdlib errors, for example — record the open decision in fenbs before updating the rule files.
- Connect your AI tools from Integrations so they read the current rules before starting work on the codebase.
What a rule file cannot do in a Go project
A Cursor rule tells the assistant how to write new code. It does not prevent it from importing a package if the import is syntactically valid; the compiler enforces that. It does not run the linter or the test suite — you need to do that yourself. Rules work best as reminders for the decisions a person made, not as enforcement mechanisms.
Project-specific business rules — which API endpoints exist, what the expected response format is, which third-party service is the approved payment provider — belong in your project notes in fenbs, not in a language rule file. See the cursor rules for AI projects article for how to combine coding rules with project context.
Go's built-in tooling deserves a mention in your rules. go vet catches common mistakes, and golangci-lint covers a wider range of static checks. Reference your project's lint configuration in a rule rather than duplicating each check. A rule that says "run go vet and golangci-lint before considering a change complete" is more maintainable than a rule that lists every individual check by name.
When the team upgrades the Go version, review the rule files for advice that may have changed. Features available in a newer version may warrant a rule update, and patterns now handled by the language itself may no longer need an explicit instruction. A brief review after any dependency update keeps the rules accurate without letting them accumulate outdated guidance. A rule that names a function removed in the new standard library is worse than no rule at all.
Context propagation is one of the areas where Go projects diverge most from each other. Some pass context only to I/O-bound operations; others thread it through every function. A rule that says "context.Context is always the first argument in any function that calls the network, a database, or a long-running operation" makes the team's decision clear to the assistant. If your project uses a request-scoped logger or trace ID stored in context values, name the key type and where it is set, so the assistant does not introduce a different approach that conflicts with the existing pattern.