Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions internal/infra/agent/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func builtinAgents() map[string]domainagent.Agent {
Command: []string{"claude"},
EnvForward: []string{"ANTHROPIC_API_KEY", "CLAUDE_*", "NODE_OPTIONS"},
NodeHeapPercent: 75,
GoMemLimitPercent: 70,
DefaultCPUs: 2,
DefaultMemory: bytesize.ByteSize(4096),
DefaultTmpSize: bytesize.ByteSize(2048),
Expand Down Expand Up @@ -97,6 +98,7 @@ func builtinAgents() map[string]domainagent.Agent {
Image: "ghcr.io/stacklok/brood-box/codex:latest",
Command: []string{"codex"},
EnvForward: []string{"OPENAI_API_KEY", "CODEX_*"},
GoMemLimitPercent: 70,
DefaultCPUs: 2,
DefaultMemory: bytesize.ByteSize(4096),
DefaultTmpSize: bytesize.ByteSize(2048),
Expand Down Expand Up @@ -127,6 +129,7 @@ func builtinAgents() map[string]domainagent.Agent {
Image: "ghcr.io/stacklok/brood-box/opencode:latest",
Command: []string{"opencode"},
EnvForward: []string{"ANTHROPIC_API_KEY", "OPENAI_API_KEY", "OPENROUTER_API_KEY", "OPENCODE_*"},
GoMemLimitPercent: 70,
DefaultCPUs: 2,
DefaultMemory: bytesize.ByteSize(4096),
DefaultTmpSize: bytesize.ByteSize(2048),
Expand Down
7 changes: 7 additions & 0 deletions pkg/domain/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ type Agent struct {
// until the guest OOM killer fires.
NodeHeapPercent uint32

// GoMemLimitPercent sets GOMEMLIMIT to this percentage of the
// effective VM memory. Zero disables the cap. This prevents Go
// tools spawned by the agent (e.g. golangci-lint) from growing
// unbounded until the guest OOM killer fires — the Go GC does
// not auto-detect VM memory limits (no cgroup boundary).
GoMemLimitPercent uint32

// DefaultCPUs is the default number of vCPUs for this agent.
DefaultCPUs uint32

Expand Down
8 changes: 8 additions & 0 deletions pkg/sandbox/sandbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,14 @@ func (s *SandboxRunner) Prepare(ctx context.Context, agentName string, opts RunO
envVars["NODE_OPTIONS"] = fmt.Sprintf("--max-old-space-size=%d", heapMiB)
}

// Cap Go GC soft memory limit. The Go runtime does not auto-detect VM
// memory boundaries (no cgroup), so without GOMEMLIMIT tools like
// golangci-lint grow unbounded until the OOM killer fires.
if ag.GoMemLimitPercent > 0 {
limitMiB := ag.DefaultMemory.MiB() * ag.GoMemLimitPercent / 100
envVars["GOMEMLIMIT"] = fmt.Sprintf("%dMiB", limitMiB)
}

allPatterns := ag.EnvForward
if len(opts.EnvForwardExtra) > 0 {
allPatterns = mergeEnvPatterns(allPatterns, opts.EnvForwardExtra)
Expand Down