- Go 1.26+
- Task (task runner)
- golangci-lint
- goimports
- GitHub CLI (
gh) (fortask buildto download pre-built runtime artifacts)
For running VMs:
- Linux with KVM support, or macOS with Hypervisor.framework (Apple Silicon)
For building go-microvm-runner from source (optional, task build-dev-system):
libkrun-develpackage installed (Linux) or Homebrew libkrun (macOS)
git clone https://github.com/stacklok/brood-box.git
cd brood-box
# Install dependencies
task tidy
# Run the full verification pipeline
task verify| Command | Description |
|---|---|
task build |
Build self-contained bbox with embedded go-microvm runtime |
task build-init |
Cross-compile bbox-init for guest VM (Linux only) |
task build-dev |
Alias for task build (embedded runtime) |
task build-dev-darwin |
Alias for task build on macOS |
task build-dev-system |
Build bbox + bin/go-microvm-runner from system libkrun (requires libkrun-devel) |
task build-dev-system-darwin |
Same as build-dev-system for macOS (requires Homebrew libkrun) |
task fetch-runtime |
Download pre-built go-microvm runtime from GitHub Release |
task fetch-firmware |
Optional: prefetch go-microvm firmware (runtime also downloads) |
task test |
Run tests with race detector |
task test-coverage |
Run tests with coverage report |
task lint |
Run golangci-lint |
task lint-fix |
Run golangci-lint with auto-fix |
task fmt |
Run go fmt + goimports |
task tidy |
Run go mod tidy |
task verify |
Full pipeline: fmt + lint + test |
task run -- <args> |
Build and run with arguments |
task clean |
Remove bin/ and coverage files |
task image-base |
Build base guest image |
task image-claude-code |
Build claude-code guest image |
task image-codex |
Build codex guest image |
task image-opencode |
Build opencode guest image |
task image-gemini |
Build gemini guest image |
task image-all |
Build all guest images |
task image-push |
Push all images to GHCR |
Edit internal/infra/agent/registry.go and add an entry to the
builtinAgents() function:
"my-agent": {
Name: "my-agent",
Image: "ghcr.io/stacklok/brood-box/my-agent:latest",
Command: []string{"my-agent"},
EnvForward: []string{"MY_API_KEY", "MY_AGENT_*"},
DefaultCPUs: 2,
DefaultMemory: 2048,
},Then update the CLI help text in cmd/bbox/main.go and the
documentation.
Domain tests are pure unit tests with no I/O. Use the injectable
EnvProvider interface for env forwarding tests:
provider := &staticEnvProvider{vars: []string{"KEY=value"}}
result := agent.ForwardEnv([]string{"KEY"}, provider)The SandboxRunner is tested with mock implementations of all interfaces.
See pkg/sandbox/sandbox_test.go for the pattern:
runner := sandbox.NewSandboxRunner(sandbox.SandboxDeps{
Registry: &mockRegistry{...},
VMRunner: &mockVMRunner{...},
Terminal: &mockTerminal{...},
Config: &sandbox.SandboxConfig{...},
EnvProvider: &mockEnvProvider{...},
Logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
// Snapshot isolation deps (nil to disable review)
WorkspaceCloner: &mockCloner{...},
Differ: &mockDiffer{...},
Reviewer: &mockReviewer{...},
Flusher: &mockFlusher{...},
})infra/config/loader_test.gotests YAML parsing with temp files- VM and SSH packages are integration-heavy and tested via the app layer mocks (actual VM tests require a running libkrun environment)
Every .go file must start with:
// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
// SPDX-License-Identifier: Apache-2.0Every .yaml file must start with:
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
# SPDX-License-Identifier: Apache-2.0Use log/slog exclusively. No fmt.Println or log.Printf.
s.logger.Info("starting VM", "name", cfg.Name, "cpus", cfg.CPUs)
s.logger.Error("failed to stop", "error", err)Wrap errors with context using %w:
return fmt.Errorf("starting VM: %w", err)pkg/domain/must NOT import frominternal/infra/orpkg/sandbox/pkg/sandbox/may import frompkg/domain/only (never frominternal/infra/)internal/infra/may import frompkg/domain/(to implement interfaces)cmd/wires everything together
- Imperative mood commit messages ("Add feature" not "Added feature")
- Capitalize the first letter
- No trailing period
- Never use
git add -A-- stage specific files only
Before submitting changes:
task fmt # Format code
task lint # Check for issues
task test # Run tests with race detector
task build # Verify compilationOr run them all at once:
task verify