
go-core
by JaimeStill
Architecture for hierarchical Claude context using plugins, skills, rules, and other features.
SKILL.md
name: go-core description: > Core Go development patterns and idioms. Use for package design, code organization, configuration patterns, interface definitions, or when editing .go files. Triggers: package structure, dependency hierarchy, interface contracts, config transformation, encapsulation, layered organization, parameter encapsulation, modern Go idioms.
Go Core Development
When This Skill Applies
- Designing package structure
- Organizing code within files
- Implementing configuration patterns
- Defining interfaces and contracts
- Working with dependencies between packages
- Any Go file editing
Principles
1. Configuration Transformation Pattern
Configuration packages serve as ephemeral data containers that transform into domain objects at package boundaries.
Key Pattern:
- Configuration types handle: structure, defaults, serialization, merging
- Domain creation happens via finalization/validation functions
- Runtime behavior depends on initialized state, not configuration values
- Configuration should not persist beyond initialization phase
// Configuration: structure and defaults only
type ServerConfig struct {
Host string `toml:"host"`
Port int `toml:"port"`
Timeout time.Duration `toml:"timeout"`
}
// Transformation: config → domain object
func NewServer(cfg ServerConfig) (*Server, error) {
if cfg.Port == 0 {
cfg.Port = 8080 // Default
}
return &Server{
addr: fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
timeout: cfg.Timeout,
}, nil
}
Decision Framework:
- Type 1 (Initialization-Only): Config discarded after creating domain object
- Type 2 (Immutable Runtime Settings): Config stored throughout object lifetime
- Type 3 (Mutable Runtime Settings): Config with validated setters and mutex protection
2. Encapsulation & Data Access Pattern
Never expose direct field access to nested structures; always provide semantic getter methods.
Bad:
// Exposes internal structure, fragile to changes
chunk.Choices[0].Delta.Content
Good:
// Semantic getter encapsulates access logic
func (c *Chunk) ExtractContent() string {
if len(c.Choices) == 0 {
return ""
}
return c.Choices[0].Delta.Content
}
// Usage
content := chunk.ExtractContent()
Benefits:
- Hides internal structure complexity
- Bounds checking in one place
- Easier refactoring
3. Layered Code Organization
Structure code within files in dependency order: foundational types first.
Order:
- Package declaration
- Imports
- Constants
- Global variables
- Interfaces
- Pure types/enums (data structures without methods)
- Structures + methods (grouped together)
- Standalone functions
package example
import "context"
// Constants
const DefaultTimeout = 30 * time.Second
// Interfaces
type Repository interface {
Find(ctx context.Context, id string) (*Entity, error)
}
// Pure types
type EntityType string
const (
TypeA EntityType = "a"
TypeB EntityType = "b"
)
// Structures with methods
type Entity struct {
ID string
Type EntityType
}
func (e *Entity) Validate() error {
if e.ID == "" {
return errors.New("id required")
}
return nil
}
// Standalone functions
func NewEntity(id string, t EntityType) *Entity {
return &Entity{ID: id, Type: t}
}
4. Parameter Encapsulation Rule
If a function requires more than 2 parameters, encapsulate them into a structure.
Bad:
func Execute(ctx context.Context, capability string, input string,
timeout time.Duration, retries int, cache bool) (*Result, error)
Good:
type ExecuteRequest struct {
Capability string
Input string
Timeout time.Duration
Retries int
UseCache bool
}
func Execute(ctx context.Context, req ExecuteRequest) (*Result, error)
Benefits:
- Self-documenting named fields
- Optional parameters through zero values
- Easier extension without breaking existing calls
5. Interface-Based Layer Interconnection
Layers should interconnect exclusively through interfaces, not concrete types.
// Interface defines public API
type Renderer interface {
Render(input []byte) ([]byte, error)
}
// Constructor returns interface, not concrete type
func NewImageMagickRenderer(cfg ImageConfig) (Renderer, error) {
return &imageMagickRenderer{cfg: cfg}, nil
}
// Consumer stores interface dependency
type PDFDocument struct {
renderer Renderer // Interface, not *imageMagickRenderer
}
func NewPDFDocument(r Renderer) *PDFDocument {
return &PDFDocument{renderer: r}
}
6. Package Dependency Hierarchy
Maintain clear, unidirectional dependencies flowing from high-level to low-level packages.
Level 0: observability/ (no dependencies)
↓
Level 1: messaging/ (depends on observability)
↓
Level 2: hub/ (depends on messaging)
↓
Level 3: state/ (depends on observability)
↓
Level 4: workflows/ (depends on state + observability)
Rules:
- Lower layers cannot import higher layers
- Prevents circular dependencies
- Each layer validates independently
- Higher layers depend on lower-level interfaces
7. Package Organization Depth Limitation
Avoid package subdirectories deeper than one level.
Good:
pkg/
├── image/
├── cache/
└── document/
Bad:
pkg/
└── document/
└── formats/
└── processors/
└── types/
Deep nesting signals architectural problems. Ask: Should this be a separate package?
8. Contract Interface Pattern
Lower-level packages define minimal interfaces that higher-level packages implement.
// In pkg/cache (lower level)
type Logger interface {
Log(ctx context.Context, level string, msg string)
}
// Cache uses the interface, doesn't import logger package
type Cache struct {
logger Logger
}
func NewCache(logger Logger) *Cache {
return &Cache{logger: logger}
}
// In pkg/logger (higher level) - implements the contract
type SlogAdapter struct {
slog *slog.Logger
}
func (a *SlogAdapter) Log(ctx context.Context, level, msg string) {
a.slog.Log(ctx, parseLevel(level), msg)
}
// Usage: dependency injection
cache := NewCache(&SlogAdapter{slog: slog.Default()})
9. Modern Go Idioms (Go 1.25+)
Leverage latest language features and standard library methods.
// sync.WaitGroup.Go() - Combines Add(1) + goroutine launch + implicit Done()
var wg sync.WaitGroup
for _, task := range tasks {
wg.Go(func() {
process(task)
})
}
wg.Wait()
// for range n - Integer range without index variable
workers := min(runtime.NumCPU()*2, len(tasks))
for range workers {
wg.Go(func() { /* worker */ })
}
// min()/max() built-ins
limit := min(requested, maxAllowed)
// errors.Join() - Combine multiple errors
var errs []error
for _, item := range items {
if err := validate(item); err != nil {
errs = append(errs, err)
}
}
return errors.Join(errs...)
// defer close(channel) - Always in sender goroutine
go func() {
defer close(results)
for item := range input {
results <- process(item)
}
}()
Anti-Patterns
Leaky Configuration
// Bad: Config persists and is accessed at runtime
type Service struct {
config Config // Stored and used later
}
func (s *Service) Process() {
timeout := s.config.Timeout // Accessing config at runtime
}
// Good: Config transformed at construction
type Service struct {
timeout time.Duration // Only the needed value stored
}
func NewService(cfg Config) *Service {
return &Service{timeout: cfg.Timeout}
}
God Packages
// Bad: Package does too many things
package utils
func ParseJSON() {}
func SendEmail() {}
func ResizeImage() {}
func ValidateInput() {}
// Good: Single responsibility packages
package json
package email
package image
package validation
Circular Dependencies
// Bad: A imports B, B imports A
package a
import "project/b"
package b
import "project/a" // Circular!
// Good: Extract shared interface to lower level
package contracts
type Processor interface { Process() }
package a
import "project/contracts"
package b
import "project/contracts"
スコア
総合スコア
リポジトリの品質指標に基づく評価
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
レビュー
レビュー機能は近日公開予定です