一键导入
go-workflow
Go project workflow guidelines. Activate when working with Go files (.go), go.mod, Go modules, golang, or Go-specific tooling.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Go project workflow guidelines. Activate when working with Go files (.go), go.mod, Go modules, golang, or Go-specific tooling.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Language-agnostic API design patterns covering REST and GraphQL, including resource naming, HTTP methods, status codes, versioning, pagination, filtering, authentication, error handling, and schema design. Activate when working with APIs, REST endpoints, GraphQL schemas, API documentation, OpenAPI/Swagger, JWT, OAuth2, endpoint design, API versioning, rate limiting, or GraphQL resolvers.
Git workflow and commit guidelines. Trigger keywords: git, commit, push, .git, version control. MUST be activated before ANY git commit, push, or version control operation. Includes security scanning for secrets (API keys, tokens, .env files), commit message formatting with HEREDOC, logical commit grouping (docs, test, feat, fix, refactor, chore, build, deps), push behavior rules, safety rules for hooks and force pushes, and CRITICAL safeguards for destructive operations (filter-branch, gc --prune, reset --hard). Activate when user requests committing changes, pushing code, creating commits, rewriting history, or performing any git operations including analyzing uncommitted changes.
Testing workflow patterns and quality standards. Activate when working with tests, test files, test directories, code quality tools, coverage reports, or testing tasks. Includes zero-warnings policy, targeted testing during development, mocking patterns, and best practices across languages.
Ansible automation workflow guidelines. Activate when working with Ansible playbooks, ansible-playbook, inventory files (.yml, .ini), or Ansible-specific patterns.
Claude Code AI-assisted development workflow. Activate when discussing Claude Code usage, AI-assisted coding, prompting strategies, or Claude Code-specific patterns.
Guidelines for containerized projects using Docker, Dockerfile, docker-compose, container, and containerization. Covers multi-stage builds, security, signal handling, entrypoint scripts, and deployment workflows.
| name | go-workflow |
| description | Go project workflow guidelines. Activate when working with Go files (.go), go.mod, Go modules, golang, or Go-specific tooling. |
| location | user |
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Guidelines for working with Go projects using modern tooling.
| Task | Tool | Command |
|---|---|---|
| Lint | golangci-lint | golangci-lint run |
| Format | goimports | goimports -w . |
| Build | go build | go build ./... |
| Test | go test | go test ./... |
| Coverage | go test | go test -cover ./... |
| Fuzzing | native | go test -fuzz=Fuzz |
| Race detection | built-in | go test -race ./... |
| Vulnerability | govulncheck | govulncheck ./... |
go mod tidy after adding or removing dependenciesreplace directives unless for local development// Good: explicit version
require github.com/pkg/errors v0.9.1
// Avoid: pseudo-versions when tagged releases exist
require github.com/pkg/errors v0.0.0-20210101000000-abcdef123456
go mod verify to check integrity# Update all dependencies
go get -u ./...
# Update specific dependency
go get -u github.com/pkg/errors
# Update to specific version
go get github.com/pkg/errors@v0.9.1
# Remove unused dependencies
go mod tidy
fmt.Errorf and %w// Good: wrapped with context
if err != nil {
return fmt.Errorf("failed to open config file %s: %w", path, err)
}
// Bad: loses error chain
if err != nil {
return fmt.Errorf("failed to open config: %v", path)
}
error interfacetype NotFoundError struct {
Resource string
ID string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("%s with ID %s not found", e.Resource, e.ID)
}
errors.Is() for sentinel error comparisonerrors.As() for type assertion on errors// Good: unwraps error chain
if errors.Is(err, os.ErrNotExist) {
// handle missing file
}
// Good: extract typed error
var notFound *NotFoundError
if errors.As(err, ¬Found) {
// handle not found
}
// Bad: direct comparison (breaks with wrapping)
if err == os.ErrNotExist {
// may not match wrapped errors
}
errors.New() for simple sentinel errorsvar (
ErrNotFound = errors.New("resource not found")
ErrUnauthorized = errors.New("unauthorized access")
)
context.Context as the first parameterctx// Good
func FetchUser(ctx context.Context, id string) (*User, error) {
// ...
}
// Bad: context not first
func FetchUser(id string, ctx context.Context) (*User, error) {
// ...
}
context.WithTimeout or context.WithDeadline for operations with time limitsfunc ProcessItems(ctx context.Context, items []Item) error {
for _, item := range items {
select {
case <-ctx.Done():
return ctx.Err()
default:
if err := process(ctx, item); err != nil {
return err
}
}
}
return nil
}
context.WithValue for passing optional parameterstype contextKey string
const userIDKey contextKey = "userID"
func WithUserID(ctx context.Context, id string) context.Context {
return context.WithValue(ctx, userIDKey, id)
}
func UserIDFromContext(ctx context.Context) (string, bool) {
id, ok := ctx.Value(userIDKey).(string)
return id, ok
}
sync.WaitGroup to wait for goroutines to completefunc ProcessConcurrently(ctx context.Context, items []Item) error {
var wg sync.WaitGroup
errCh := make(chan error, len(items))
for _, item := range items {
wg.Add(1)
go func(item Item) {
defer wg.Done()
defer func() {
if r := recover(); r != nil {
errCh <- fmt.Errorf("panic: %v", r)
}
}()
if err := process(ctx, item); err != nil {
errCh <- err
}
}(item)
}
wg.Wait()
close(errCh)
for err := range errCh {
if err != nil {
return err
}
}
return nil
}
// Good: producer closes channel
func Generate(ctx context.Context, n int) <-chan int {
ch := make(chan int)
go func() {
defer close(ch)
for i := 0; i < n; i++ {
select {
case <-ctx.Done():
return
case ch <- i:
}
}
}()
return ch
}
sync.Mutex for protecting shared statesync.RWMutex when reads significantly outnumber writessync.Once for one-time initializationtype Cache struct {
mu sync.RWMutex
items map[string]Item
}
func (c *Cache) Get(key string) (Item, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
item, ok := c.items[key]
return item, ok
}
func (c *Cache) Set(key string, item Item) {
c.mu.Lock()
defer c.mu.Unlock()
c.items[key] = item
}
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -1, -2, -3},
{"zero", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected)
}
})
}
}
testdata/ directorytestdata/ directory is ignored by the Go toolchainfunc TestParseConfig(t *testing.T) {
data, err := os.ReadFile("testdata/config.json")
if err != nil {
t.Fatal(err)
}
// use data...
}
t.Helper() in test helper functionstesting.TB to work with both tests and benchmarksfunc assertNoError(t testing.TB, err error) {
t.Helper()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
-race flag in CIgo test -race ./... locally before pushing# CI configuration
go test -race -coverprofile=coverage.out ./...
myproject/
├── cmd/ # Main applications
│ └── myapp/
│ └── main.go
├── internal/ # Private application code
│ ├── config/
│ ├── handlers/
│ └── service/
├── pkg/ # Public library code
│ └── client/
├── api/ # API definitions (OpenAPI, proto)
├── web/ # Web assets
├── scripts/ # Build and CI scripts
├── testdata/ # Test fixtures
├── go.mod
├── go.sum
└── Makefile
cmd/ SHOULD contain only main packages with minimal logicinternal/ MUST contain code that SHOULD NOT be imported by other projectspkg/ MAY contain code intended for external usemain package SHOULD be minimal// cmd/myapp/main.go
package main
import (
"log"
"os"
"myproject/internal/app"
)
func main() {
if err := app.Run(os.Args[1:]); err != nil {
log.Fatal(err)
}
}
// Good
func ProcessUsers(users []User) error {
for i, u := range users {
// short names ok for loop variables
}
}
// Bad
func ProcessUsers(users []User) error {
for index, user := range users {
// unnecessarily verbose
}
}
// Good
package http
// Bad
package httpClient
package http_client
// Good
type Reader interface {
Read(p []byte) (n int, err error)
}
type UserService interface {
GetUser(ctx context.Context, id string) (*User, error)
}
// Bad
type IUserService interface {
GetUser(ctx context.Context, id string) (*User, error)
}
// Good
var httpClient *http.Client
var HTTPClient *http.Client // exported
var userID string
var UserID string // exported
// Bad
var HttpClient *http.Client
var userId string
// Good: accepts interface
func ProcessData(r io.Reader) error {
// can accept any Reader
}
// Good: returns concrete type
func NewService(db *sql.DB) *Service {
return &Service{db: db}
}
// Bad: returns interface (unless abstracting implementations)
func NewService(db *sql.DB) ServiceInterface {
return &Service{db: db}
}
// Good: small, focused interfaces
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader
Writer
}
// In consumer package
type UserGetter interface {
GetUser(ctx context.Context, id string) (*User, error)
}
// Service implementation doesn't need to know about this interface
func NewHandler(users UserGetter) *Handler {
return &Handler{users: users}
}
type Server struct {
addr string
timeout time.Duration
}
type Option func(*Server)
func WithTimeout(d time.Duration) Option {
return func(s *Server) {
s.timeout = d
}
}
func NewServer(addr string, opts ...Option) *Server {
s := &Server{
addr: addr,
timeout: 30 * time.Second, // default
}
for _, opt := range opts {
opt(s)
}
return s
}
func main() {
ctx, cancel := signal.NotifyContext(context.Background(),
syscall.SIGINT, syscall.SIGTERM)
defer cancel()
srv := &http.Server{Addr: ":8080"}
go func() {
<-ctx.Done()
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(shutdownCtx)
}()
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
}
go build ./... to verify compilationgo test -race ./... for race detectiongolangci-lint run for static analysisgovulncheck ./... for vulnerability scanningname: Go
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- run: go build ./...
- run: go test -race -coverprofile=coverage.out ./...
- run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
- run: golangci-lint run
- run: go install golang.org/x/vuln/cmd/govulncheck@latest
- run: govulncheck ./...