$ npx rulesync-cli pull✓ Wrote CLAUDE.md (2 rulesets)# Coding Standards- Always use async/await- Prefer named exports
Comparisons

AI Rules: Python vs Go Conventions

Python and Go have opposite philosophies: Python is flexible and expressive, Go is simple and explicit. Each needs different AI rules for error handling, concurrency, project structure, testing, and style enforcement.

7 min read·June 9, 2025

Python: many valid patterns, rule picks which. Go: few choices, language enforces conventions. Different rule needs entirely.

Error handling, concurrency, project structure, testing, style enforcement, and rules for each language

Opposite Philosophies, Different AI Rules

Python's philosophy: "There should be one — and preferably only one — obvious way to do it." In practice: Python offers multiple ways to do everything (classes, functions, decorators, generators, comprehensions, async, sync). The AI must know: which Python patterns YOUR project uses. Python AI rules guide: which of the many Python idioms to prefer. Go's philosophy: "Less is exponentially more." In practice: Go has one way to do most things (no generics until recently, no exceptions, no ternary, explicit error handling). The AI needs fewer Go rules because: Go has fewer choices to make.

Without language-specific rules: the AI generates Python with too many patterns (list comprehensions in one function, for loops in the next, inconsistent error handling) or Go with Python-isms (try/except in Go which does not exist, class-based patterns in a struct language). The language rule must be: the first line of every CLAUDE.md. The AI must know: which language it is generating, and which idioms that language uses in this project.

This article provides: the key convention differences between Python and Go, the AI rules needed for each, and templates for both. The comparison highlights: where language philosophy creates different AI rule needs and how to write rules that match each language's idioms.

Error Handling: Exceptions vs Error Returns

Python error handling: exceptions. try/except/finally for error control flow. raise ValueError("Invalid input") for expected errors. Custom exception classes (class NotFoundError(Exception): pass). The AI should know: your project error handling convention. Rule options: "Raise custom exceptions for domain errors (NotFoundError, ValidationError). Use try/except at API boundaries. Never bare except: — always except SpecificError." Or: "Return Result types (from returns library or custom) for expected errors. Raise only for unexpected errors."

Go error handling: explicit error returns. func GetUser(id string) (*User, error) { ... }. if err != nil { return nil, fmt.Errorf("getting user: %w", err) }. No exceptions, no try/catch. Errors are values returned from functions. The AI rule: "Always return error as the last return value. Check err != nil immediately after every function call that returns an error. Wrap errors with context: fmt.Errorf("doing X: %w", err). Never ignore returned errors (use _ only when explicitly documented why)."

The error handling rule is: the most impactful language-specific rule. In Python: the AI must know whether to raise exceptions or return Result types (both are valid Python). In Go: the AI must always return and check errors (the only Go pattern). AI generating Python-style try/except in Go: compilation error. AI generating Go-style error returns in Python: technically works but is non-idiomatic. The language determines: the error handling paradigm. The rule specifies: which variant within the paradigm.

  • Python: raise exceptions (custom classes) or return Result types — your rule specifies which
  • Go: return error values, check err != nil, wrap with fmt.Errorf — the only Go pattern
  • Python rule: 'Raise custom exceptions for domain errors. Never bare except:'
  • Go rule: 'Return error as last value. Check err != nil. Wrap with context. Never ignore errors'
  • AI error: try/except in Go = compilation error. Go-style error returns in Python = non-idiomatic
💡 The Most Impactful Language-Specific Rule

Python: 'Raise custom exceptions for domain errors' or 'Return Result types for expected errors' — the rule picks between two valid Python approaches. Go: 'Return error, check err != nil, wrap with context' — the only Go pattern. Error handling is: the rule that most defines language-specific AI behavior.

Concurrency: asyncio vs Goroutines

Python concurrency: asyncio (async/await for I/O-bound concurrency), threading (for I/O parallelism with the GIL), and multiprocessing (for CPU-bound parallelism). The AI must know: which concurrency model the project uses. Rule: "Use asyncio for all I/O operations (database, HTTP, file). async def for handlers, await for I/O calls. For CPU-bound work: use multiprocessing or offload to a task queue (Celery, Dramatiq). Never use threading for CPU work (GIL limits to one thread)."

Go concurrency: goroutines and channels. go func() { ... }() launches a goroutine. Channels (chan) communicate between goroutines. sync.WaitGroup for waiting on multiple goroutines. context.Context for cancellation and timeouts. The AI rule: "Use goroutines for concurrent operations. Channels for communication between goroutines. context.Context for cancellation — pass as first parameter to every function that does I/O. sync.WaitGroup for waiting on multiple goroutines. Never share memory between goroutines without sync.Mutex or channels."

The concurrency rule matters because: AI trained on both languages may generate asyncio patterns in Go (await does not exist) or goroutine patterns in Python (go keyword does not exist). The rule specifies: the concurrency primitives of the current language. For Python: asyncio is the standard for web applications (FastAPI, aiohttp). For Go: goroutines are the standard for everything (built into the language). One concurrency rule per language prevents: every concurrent code generation error.

⚠️ await Does Not Exist in Go

AI trained on both languages: may generate asyncio patterns in Go (await does not exist) or goroutine patterns in Python (go keyword does not exist). The concurrency rule specifies: which primitives the current language uses. One rule prevents: every concurrent code generation error from language confusion.

Project Structure: Packages vs Modules

Python project structure: src/ layout with packages (directories with __init__.py). src/app/models/user.py, src/app/services/user_service.py, src/app/routes/users.py. Import: from app.models.user import User. Virtual environment: venv or poetry. Dependency management: requirements.txt, pyproject.toml, or poetry.lock. AI rule: "Python project in src/app/. Import: from app.module.file import Name. Dependencies: poetry (pyproject.toml + poetry.lock). Virtual env: managed by poetry."

Go project structure: go modules with packages (directories without special files). cmd/api/main.go (entry point), internal/user/model.go, internal/user/service.go, internal/user/handler.go. Import: import "github.com/org/project/internal/user". Dependency management: go.mod + go.sum. AI rule: "Go project with go modules. Entry: cmd/api/main.go. Business logic: internal/ (not importable by external packages). Import by full module path. Dependencies: go.mod (go get to add)."

The structure rule prevents: Python-style flat imports in Go (import user does not work without the full module path), Go-style internal/ convention in Python (Python does not enforce internal by directory name), and wrong dependency management commands (pip install in a Go project, go get in a Python project). Each language has: its own project layout convention. The rule tells the AI: where to create files, how to import them, and how to manage dependencies.

  • Python: src/app/ packages, from app.module import Name, poetry for deps
  • Go: cmd/ + internal/ structure, full module path imports, go.mod for deps
  • Python __init__.py: makes directories into packages. Go: no special files needed
  • Go internal/: not importable by external packages (enforced by compiler)
  • AI error: pip install in Go project, go get in Python project — wrong package manager

Testing and Style Enforcement

Python testing: pytest (the standard). Test files: test_*.py or *_test.py. Fixtures: @pytest.fixture. Assertions: assert user.name == 'Alice' (plain assert, pytest enhances error output). Mocking: unittest.mock or pytest-mock. AI rule: "pytest for all tests. Fixtures for setup. Plain assert for assertions. pytest-mock for mocking. Test files: test_user_service.py alongside source or in tests/ directory."

Go testing: testing package (standard library). Test files: *_test.go in the same package. Test functions: func TestGetUser(t *testing.T) { ... }. Assertions: if got != want { t.Errorf("got %v, want %v", got, want) } (no assertion library by default, or use testify). Benchmarks: func BenchmarkGetUser(b *testing.B) { ... }. AI rule: "Go testing package. Test files: *_test.go same package. Test functions: TestXxx(t *testing.T). Use testify for assertions if in go.mod. Table-driven tests for multiple cases."

Style enforcement: Python uses: Black (formatter), Ruff or flake8 (linter), mypy or pyright (type checker). Go uses: gofmt (formatter, mandatory — all Go code is gofmt'd), go vet (linter, catches common mistakes), golangci-lint (comprehensive linter). The key difference: Go style is enforced by the language toolchain (gofmt is not optional). Python style is enforced by chosen tools (Black is popular but not mandatory). The AI rule for Go: no style rules needed (gofmt handles everything). For Python: specify which formatter and linter the project uses.

ℹ️ Go Needs Fewer Rules: The Language Enforces Conventions

Python: many valid patterns, the rule file picks which. Go: gofmt enforces style (no style rules needed), error returns are mandatory (no exception rules needed), and the language has fewer patterns overall. Go CLAUDE.md files are naturally shorter because: the language makes more decisions for you.

Language Rule Summary

Summary of AI rules for Python vs Go.

  • Error handling: Python = exceptions (or Result types). Go = error returns with err != nil checks
  • Concurrency: Python = asyncio for I/O, multiprocessing for CPU. Go = goroutines + channels + context
  • Structure: Python = src/app/ packages + poetry. Go = cmd/ + internal/ + go.mod
  • Testing: Python = pytest + fixtures + assert. Go = testing pkg + TestXxx + table-driven
  • Style: Python = Black + Ruff (chosen tools). Go = gofmt (mandatory, no style rules needed)
  • Python needs more AI rules: many valid patterns, rule specifies which to prefer
  • Go needs fewer AI rules: fewer choices, language enforces conventions (gofmt, error returns)
  • Both need: language as first rule line, error handling convention, testing framework, project structure