This document provides guidelines for AI coding assistants working on this Go project.
jj-diff/
├── cmd/jj-diff/ # CLI entry point
├── internal/
│ ├── model/ # Core TEA model (orchestrator)
│ ├── jj/ # jj CLI integration
│ ├── diff/ # Parser and patch generator
│ ├── search/ # Search functionality
│ ├── fuzzy/ # Fuzzy matching
│ ├── components/ # UI components
│ ├── config/ # Configuration
│ └── theme/ # Catppuccin themes
└── go.mod
- One package = one purpose
- Package names: short, lowercase, no underscores (
httputilnothttp_util) - Avoid
util,common,miscpackages internal/prevents external imports at the compiler level
- Group related types, functions, and methods in the same file
- Name files after the primary type they contain (
user.go,user_test.go) - Keep
main.gominimal
func ValidateUser(u User) error {
if err := validateEmail(u.Email); err != nil {
return err
}
return validateAge(u.Age)
}- Define interfaces where they're used, not where they're implemented
- Keep interfaces small (1-3 methods)
- Avoid interface pollution
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}
for _, opt := range opts {
opt(s)
}
return s
}- Errors are values; handle them explicitly
- Return errors, don't panic (except for truly unrecoverable states)
- Add context when wrapping:
fmt.Errorf("doing something: %w", err) - Use
errors.Isanderrors.Asfor checking errors - Use custom error types for domain-specific errors
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -1, -1, -2},
{"zero", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Add(tt.a, tt.b)
if got != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.expected)
}
})
}
}- Use
_testpackage suffix for black-box testing - Place test files adjacent to the code they test
- Naked returns: Always name what you're returning
- Long functions: If > 50 lines, consider breaking up
- Deep nesting: Use early returns to flatten
- Interface pollution: Don't define interfaces until needed
- Ignoring errors:
_ = doThing()is almost always wrong - Global state: Pass dependencies explicitly
- Run
mise run cibefore committing - Run
hk fixto auto-fix linting issues - Use
golangci-lint runfor detailed linting output
- Do not stage, commit, or push without explicit instruction
- Use conventional commits (commitizen enforced)