Contributing to Born

July 12, 2026 · View on GitHub

Thank you for your interest in contributing to Born! This document guides you through the contribution process.

Born is a modern ML framework for Go, and we welcome contributions of all kinds - from bug fixes to new features, documentation improvements to performance optimizations.


Table of Contents


Getting Started

Prerequisites

ToolVersionPurpose
Go1.26+Download
GitLatestVersion control
golangci-lintLatestInstall
MakeAnyBuild automation (optional)

For WebGPU development (optional):

Setup Development Environment

# Clone repository
git clone https://github.com/born-ml/born.git
cd born

# Install dependencies
go mod download

# Verify setup
make check    # Runs tests + lint + vet

# Or manually:
go test ./...
golangci-lint run

Project Structure

born/
├── internal/           # Private implementation
│   ├── tensor/         # Core tensor types and Backend interface
│   ├── backend/cpu/    # CPU backend implementation
│   ├── backend/webgpu/ # GPU backend (WebGPU)
│   ├── autodiff/       # Automatic differentiation
│   ├── nn/             # Neural network modules
│   └── optim/          # Optimizers
├── tensor/             # Public API
├── nn/                 # Public API
├── optim/              # Public API
├── examples/           # Example applications
└── docs/               # Documentation

Development Workflow

1. Check Project Status

Before starting:

2. Pick a Task

  • Issues labeled good-first-issue are great starting points
  • Issues labeled help-wanted need contributors
  • Comment on the issue to claim it before starting

3. Create a Branch

# Update main
git checkout main
git pull origin main

# Create feature branch
git checkout -b feat/your-feature

# Or for fixes
git checkout -b fix/issue-description

Branch naming conventions:

  • feat/ - New features
  • fix/ - Bug fixes
  • docs/ - Documentation
  • refactor/ - Code restructuring
  • perf/ - Performance improvements
  • hotfix/ - Urgent production fixes

4. Development

  • Write code following our Code Standards
  • Write tests (target: 70%+ coverage)
  • Update documentation if needed
  • Run checks locally before pushing

5. Testing

# All tests
make test
# Or: go test ./...

# With race detector
make test-race
# Or: go test -race ./...

# Coverage report
make coverage
# Or: go test -cover ./...

# Specific package
go test ./internal/tensor/... -v

# Single test
go test -run TestTensorAdd -v

# Benchmarks
make bench
# Or: go test -bench=. -benchmem ./...

6. Linting

We use aggressive golangci-lint configuration with 20+ linters:

# Run linter
make lint
# Or: golangci-lint run

# Auto-fix where possible
golangci-lint run --fix

Key linter requirements:

  • gofmt - Code formatting
  • govet - Go vet checks
  • errcheck - Error handling
  • staticcheck - Static analysis
  • gosec - Security checks
  • godot - Doc comments must end with period
  • gocyclo - Cyclomatic complexity < 15
  • funlen - Function length < 120 lines

If you need to disable a linter for a specific line, always add explanation:

//nolint:gosec // G404: Using math/rand for non-cryptographic shuffle

7. Submit PR

# Commit changes
git add .
git commit -m "feat(tensor): add broadcasting support"

# Push branch
git push -u origin feat/your-feature

Then create a Pull Request on GitHub.


Code Standards

Go Style

Follow Effective Go and these guidelines:

Naming:

TypeConventionExample
ExportedPascalCaseTensorAdd, NewBackend
UnexportedcamelCaseaddFloat32, memoryPool
ConstantsPascalCaseMaxBatchSize
Interfaces-er suffix when appropriateBackend, Optimizer

Example:

// Backend defines the interface for tensor computation backends.
type Backend interface {
    Add(a, b *RawTensor) *RawTensor
    MatMul(a, b *RawTensor) *RawTensor
    Name() string
}

// CPUBackend implements Backend for CPU computation.
type CPUBackend struct {
    memoryPool *MemoryPool
    workers    int
}

// Add performs element-wise addition.
func (b *CPUBackend) Add(a, c *RawTensor) *RawTensor {
    result := b.allocate(a.Shape())
    addFloat32(result.data, a.data, c.data)
    return result
}

Documentation

All exported functions/types MUST have doc comments:

  • Start with the name of the thing being described
  • Use complete sentences
  • End with a period (godot linter enforces this)
// Tensor represents a multi-dimensional array with type T and backend B.
// It provides operations for mathematical computations and automatic
// differentiation when used with an autodiff backend.
type Tensor[T DType, B Backend] struct {
    raw     *RawTensor
    backend B
}

// Add performs element-wise addition of two tensors.
// Returns a new tensor containing the result.
// Panics if shapes are incompatible.
func (t *Tensor[T, B]) Add(other *Tensor[T, B]) *Tensor[T, B] {
    // ...
}

Error Handling

Return errors for expected failures:

func LoadModel(path string) (*Model, error) {
    if _, err := os.Stat(path); os.IsNotExist(err) {
        return nil, fmt.Errorf("model file not found: %s", path)
    }
    // ...
}

Panic for programmer errors (invariant violations):

func (t *Tensor[T, B]) Shape() Shape {
    if t.raw == nil {
        panic("tensor is nil")
    }
    return t.raw.shape
}

Testing

Test naming: TestTypeName_MethodName or TestFunctionName

func TestTensor_Add(t *testing.T) {
    t.Run("compatible shapes", func(t *testing.T) {
        // ...
    })

    t.Run("broadcasting", func(t *testing.T) {
        // ...
    })
}

Table-driven tests for multiple cases:

func TestMatMul(t *testing.T) {
    tests := []struct {
        name   string
        aShape Shape
        bShape Shape
        want   Shape
    }{
        {"2x2 * 2x2", Shape{2, 2}, Shape{2, 2}, Shape{2, 2}},
        {"2x3 * 3x4", Shape{2, 3}, Shape{3, 4}, Shape{2, 4}},
        {"batch matmul", Shape{8, 2, 3}, Shape{8, 3, 4}, Shape{8, 2, 4}},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            // ...
        })
    }
}

Commit Guidelines

Format

type(scope): brief description

Detailed explanation if needed.

Fixes #123

Types

TypeDescription
featNew feature
fixBug fix
docsDocumentation only
styleCode style (no logic change)
refactorCode restructuring (no behavior change)
perfPerformance improvement
testAdding/updating tests
choreMaintenance tasks (deps, CI, etc.)

Examples

feat(tensor): implement broadcasting for binary ops

Adds NumPy-style broadcasting for Add, Sub, Mul, Div operations.
Broadcasting follows standard rules: dimensions are compared
right-to-left, and must be equal or one of them must be 1.

- Added broadcastShapes helper function
- Updated all binary ops to use broadcasting
- Added comprehensive test coverage

Closes #42
fix(webgpu): resolve buffer leak in compute shaders

Fixed GPU buffer not being released when compute shader
completes with error. Added proper cleanup in defer block.

Fixes #87
chore: update go-webgpu to v0.1.1

Updated GPU backend dependencies:
- go-webgpu/webgpu v0.1.0 → v0.1.1
- go-webgpu/goffi v0.3.1 → v0.3.3

Pull Request Process

Branch Protection

The main branch is protected:

  • Required: All CI checks must pass
  • Required: At least 1 approval (maintainers can override)
  • Direct pushes are blocked (except for admins)

Before Submitting

  • Code follows style guidelines
  • Tests written and passing (make test)
  • Linter passes (make lint)
  • Documentation updated (if needed)
  • Commit messages follow guidelines
  • No merge conflicts with main

PR Description Template

## Summary

Brief description of what this PR does.

## Changes

- Change 1
- Change 2

## Test plan

- [ ] Unit tests added/updated
- [ ] `make test` passes
- [ ] `make lint` passes
- [ ] Manual testing performed (if applicable)

## Related

Closes #123

CI Pipeline

All PRs run through CI:

CheckDescription
Unit TestsUbuntu, macOS, Windows (Go 1.26)
Lintgolangci-lint with project config
Code Formattinggofmt verification
Build ExamplesCompile all examples
Build ToolsCompile CLI tools
Build WASMGOOS=js GOARCH=wasm go build ./...
BenchmarksRun performance benchmarks
CodecovCoverage reporting

Merge Strategy

We choose the merge method based on commit history:

HistoryMerge methodRationale
Clean semantic commits (each carries a distinct change)--mergePreserves author's commit structure
Mixed/WIP commits (fixups, review changes)--squashProduces a clean single commit

If you have a preference, note it in the PR description (e.g., "please merge, not squash") and we'll respect it.

Review Process

  1. CI runs automatically on PR creation
  2. Maintainer reviews code
  3. Feedback addressed (if any)
  4. Approval and merge

Areas for Contribution

High Priority

AreaDescriptionSkills
PerformanceSIMD optimizations, GPU kernelsGo, WGSL
TestingIncrease coverage, edge casesGo
DocumentationTutorials, API docsTechnical writing
ONNX SupportMore operator implementationsML, Go

Medium Priority

AreaDescriptionSkills
WebGPU BackendNew GPU operationsWGSL, WebGPU
Model ZooPre-trained model importsML
ExamplesReal-world use casesGo, ML
QuantizationINT8/INT4 supportML, optimization

Always Welcome

  • Bug Reports - Detailed issue reports with reproduction steps
  • Bug Fixes - Any bug fixes are appreciated
  • Documentation - Improvements, corrections, translations
  • Examples - New examples demonstrating features

First-Time Contributors

Look for issues labeled:

  • good-first-issue - Simple, well-defined tasks
  • help-wanted - Tasks where we need help
  • documentation - Doc improvements

Communication

GitHub

  • Issues - Bug reports, feature requests
  • Pull Requests - Code contributions
  • Discussions - Questions, ideas, RFC

Getting Help

  1. Check existing Issues
  2. Search Discussions
  3. Read documentation in docs/
  4. Ask in GitHub Discussions

Code of Conduct

We are committed to providing a welcoming and respectful environment.

Expected behavior:

  • Be respectful and inclusive
  • Provide constructive feedback
  • Focus on the technical merits
  • Help others learn and grow

Unacceptable behavior:

  • Harassment or discrimination
  • Personal attacks
  • Trolling or inflammatory comments

Report issues to the maintainers via GitHub.


License

By contributing to Born, you agree that your contributions will be licensed under the Apache License 2.0.


Thank You!

Every contribution makes Born better. Whether it's:

  • Reporting a bug
  • Fixing a typo
  • Adding a feature
  • Improving documentation

You're helping build production-ready ML for Go.


Questions? Open a Discussion or check existing Issues.


Last Updated: 2025-12-24