Go context
26 production-grade Go skills for Claude Code, Gemini CLI, and opencode.
npx -y skills add muratmirgun/gophers --skill go-contextAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when designing, propagating, or debugging context.Context flow in Go — first-parameter placement, deadlines and cancellation, request-scoped values, WithoutCancel for fire-and-forget work, and key-collision-safe value patterns. Apply proactively whenever a function takes ctx, spawns work, or accepts request-scoped data, even if the user has not asked about context.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
6.3 KB, as published. Nobody here has run it
Go Context Usage
context.Context carries the cancellation, deadline, and request-scoped values for a single unit of work. Pass it explicitly through the entire call chain — never store it, never replace it with Background() mid-flight, never use it as a side-channel for ordinary parameters.
Core Rules
ctxis the first parameter, namedctx context.Context. No exceptions outside interface stubs imposed by external APIs.- Propagate the caller's
ctxall the way down. Do not start a new tree withcontext.Background()inside a request path. - Do not store
Contextin a struct. Pass it to each method that needs it. - Always
defer cancel()afterWithCancel/WithTimeout/WithDeadline, unless ownership is explicitly transferred. - Context values are for request-scoped metadata only (request ID, auth principal, trace). Never for optional function parameters or config.
- Value keys must be unexported named types to prevent cross-package collisions.
Where Does Data Belong?
Pick the most explicit option that fits — context values are the last resort.
| Option | Use for | Why |
|---|---|---|
| Function parameter | Anything the function needs to do its job | Type-checked, visible at call site |
| Method receiver | State that belongs to the type | Already in scope |
| Package-level config | Process-wide, immutable | One owner, no hidden flow |
context.Value | Request-scoped metadata that crosses layers without being a function arg | Untyped — use sparingly |
Read references/values-and-keys.md for the unexported-key pattern, typed accessors, and OpenTelemetry/trace propagation.
Constructors
| Situation | Use |
|---|---|
main, init, top-level test | context.Background() |
| Placeholder while plumbing is incomplete | context.TODO() |
| Inside an HTTP handler | r.Context() |
| Need manual cancellation | context.WithCancel(parent) |
| Need a deadline / timeout | context.WithTimeout(parent, d) / WithDeadline |
| Background work that must outlive the request (Go 1.21+) | context.WithoutCancel(parent) |
Propagation: The One Rule
// Bad — breaks the chain, downstream cannot be cancelled
func (s *OrderService) Create(ctx context.Context, o Order) error {
return s.db.ExecContext(context.Background(), insertSQL, o.ID)
}
// Good — same ctx flows HTTP handler -> service -> DB -> external API
func (s *OrderService) Create(ctx context.Context, o Order) error {
return s.db.ExecContext(ctx, insertSQL, o.ID)
}
Deriving and Cancelling
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel() // release resources even on the happy path
select {
case <-ctx.Done():
return ctx.Err()
case res := <-doAsync(ctx):
return res
}
Read references/cancellation-and-deadlines.md for
WithoutCancel,AfterFunc, and long-running goroutine cancellation patterns.
Don't Wrap Context in Custom Types
// Bad — pollutes the standard signature
type MyCtx interface {
context.Context
UserID() string
}
// Good — keep the signature standard, extract via helper
func UserIDFrom(ctx context.Context) (string, bool) { /* ... */ }
Enforce With Linters
Most context mistakes are mechanical and a linter will catch them in CI before review:
govet -vet=context— flags non-firstcontext.Contextparameters and lost cancels.staticcheck SA1012— calls passingnilcontext.contextcheck(golangci-lint) — verifies downstream calls propagatectx.noctx— flags HTTP/SQL APIs called without their*Contextvariant.
Run golangci-lint run --enable=contextcheck,noctx,staticcheck in CI for any project that exposes context.Context.
Anti-Patterns
| Anti-pattern | Why it hurts | Do this instead |
|---|---|---|
ctx context.Context stored on a struct field | Lifetime becomes invisible; outlives the request | Pass ctx to each method |
context.Background() mid-call | Cancellation chain breaks; goroutines leak | Use the caller's ctx |
ctx.Value("user-id") with a string key | Cross-package collisions, no type safety | Unexported key type + typed getter |
Passing nil as a context | Panics on Done() / Value() | Use context.TODO() while plumbing |
WithTimeout without defer cancel() | Leaks the timer until parent finishes | defer cancel() on the next line |
Custom MyContext interface | Breaks every standard signature | Keep context.Context, extract with helpers |
Verification Checklist
- Every function that does I/O, blocks, or calls another
ctx-aware API takesctx context.Contextas its first parameter. - No
context.Contextfield on any struct (search:ctx\s+context\.Contextinsidetype ... struct). - Every
WithCancel/WithTimeout/WithDeadlineis followed bydefer cancel()on the next line. - No
context.Background()orcontext.TODO()calls inside request handlers. - All context value keys are unexported named types, accessed via typed getters.
-
golangci-lint run --enable=contextcheck,noctxpasses.
References
- references/values-and-keys.md — unexported key types, typed accessors, trace propagation
- references/cancellation-and-deadlines.md — timeouts,
WithoutCancel,AfterFunc, goroutine cancellation - references/http-and-db.md — handlers,
NewRequestWithContext,QueryContext/ExecContext