Contributing
stereOS welcomes contributions.
Development setup
Prerequisites
- Nix with flakes enabled — Add
experimental-features = nix-command flakesto~/.config/nix/nix.conf. - direnv — See Local Build for installation.
Getting started
git clone https://github.com/<your-username>/stereos
cd stereos
direnv allow
make help
make build
make test
The Nix dev shell provides Go, linters, and all other tools.
Testing
make test
Follow existing test patterns. Use standard Go tests:
func TestConfigParsing(t *testing.T) {
cfg, err := config.Load("testdata/valid.toml")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if cfg.VM.Name != "test-vm" {
t.Errorf("expected name 'test-vm', got '%s'", cfg.VM.Name)
}
}
Linting and formatting
gofmt -w .
go vet ./...
Code that doesn’t pass these will be flagged during review.
Code style
- Error handling — Return errors, don’t panic. Wrap with context:
fmt.Errorf("loading config: %w", err). - Naming — Clear, descriptive. Avoid abbreviations except common ones (
ctx,err,cfg). - Package structure — Single responsibility per package. No circular dependencies.
- Comments — Doc comments on exported types and functions. Focus on what, not how.
- Constructor pattern — Use
New*functions. Return pointers. Initialize maps and slices.
func NewVMManager(imagePath string) *VMManager {
return &VMManager{
imagePath: imagePath,
vms: make(map[string]*VM),
}
}
Pull request process
Branch naming
git checkout -b feat/my-feature
# or: fix/issue-description, docs/page-name, refactor/component-name
Before submitting
make build— compiles without errorsmake test— all tests passgofmt -w .andgo vet ./...- One logical change per commit
PR description
Cover what the change does, why it’s needed, and testing beyond the automated suite.
Review process
All PRs need at least one review. Reviewers check correctness, test coverage, code style, docs updates, and regressions.
Project structure
stereos/
├── flake.nix # Entry point — delegates to flake/ modules (flake-parts)
├── flake/ # flake-parts modules (split flake.nix logic)
│ ├── devshell.nix # Developer shell for direnv
│ ├── images.nix # Image build targets (raw, qcow2, kernel-artifacts)
│ └── checks.nix # CI verification builds
├── modules/ # NixOS modules — the core of the OS
│ ├── default.nix # Aggregator (imports all sub-modules)
│ ├── base.nix # Core OS: filesystem, SSH, nix settings, hardening
│ ├── boot.nix # Boot config + boot-time optimizations
│ ├── services/ # Service overrides (stereosd, agentd)
│ └── users/ # User definitions (agent, admin)
├── profiles/ # Composable configuration presets
│ ├── base.nix # Shared foundation (imports image formats)
│ └── dev.nix # Dev-only: SSH key injection, debug tools
├── mixtapes/ # Mixtapes — spins with specific AI agents
│ ├── claude-code/
│ ├── opencode/
│ ├── gemini-cli/
│ └── full/
├── formats/ # Image format definitions (raw, qcow2, kernel)
├── lib/ # Shared Nix helpers (mkMixtape, SSH key logic)
├── cmd/ # CLI entry points (mb)
├── internal/ # Private Go packages
├── Makefile # Build and test targets
├── .envrc # direnv integration
└── go.mod # Go module definition