Skip to content

Global config defaults ignored when agent has built-in values #56

@JAORMX

Description

@JAORMX

Bug

Global defaults in ~/.config/broodbox/config.yaml are silently ignored for tmp_size, cpus, and memory because all built-in agents hardcode non-zero values for these fields.

Reproduction

Set a global default in ~/.config/broodbox/config.yaml:

defaults:
  tmp_size: "2g"

Run any built-in agent (e.g. bbox claude-code). The VM gets 512 MiB /tmp instead of 2 GiB.

Root cause

There are four priority levels for resource settings:

  1. CLI flag (--tmp-size) — highest
  2. Per-agent config override (agents.claude-code.tmp_size in config)
  3. Global config default (defaults.tmp_size)
  4. Agent built-in (e.g. 512 MiB hardcoded in registry) — lowest

Levels 1 and 2 are merged into a single override parameter before config.Merge() is called (pkg/sandbox/sandbox.go:240-255), so they correctly take top priority.

The bug is in how Merge() handles levels 3 vs 4. In pkg/domain/config/config.go:

// TmpSize: override > agent default > global default
if override.TmpSize > 0 {
    result.DefaultTmpSize = override.TmpSize.MiB()
}
if result.DefaultTmpSize == 0 && defaults.TmpSize > 0 {
    result.DefaultTmpSize = defaults.TmpSize.MiB()
}

The global default is only applied when result.DefaultTmpSize == 0, but all built-in agents in internal/infra/agent/registry.go hardcode DefaultTmpSize: 512. So the agent built-in always shadows the global config default.

The same issue affects CPUs (built-in: 2) and Memory (built-in: 4096).

Suggested fix

Change Merge() so global defaults beat agent built-ins when no per-agent override is set. Per-agent overrides already flow through the override parameter (not the agent), so this is safe:

// TmpSize: override > global default > agent built-in
if override.TmpSize > 0 {
    result.DefaultTmpSize = override.TmpSize.MiB()
} else if defaults.TmpSize > 0 {
    result.DefaultTmpSize = defaults.TmpSize.MiB()
}

Apply the same pattern for CPUs and Memory:

if override.CPUs > 0 {
    result.DefaultCPUs = override.CPUs
} else if defaults.CPUs > 0 {
    result.DefaultCPUs = defaults.CPUs
}

if override.Memory > 0 {
    result.DefaultMemory = override.Memory
} else if defaults.Memory > 0 {
    result.DefaultMemory = defaults.Memory
}

Why this is safe for per-agent overrides: Per-agent config overrides (e.g. agents.claude-code.tmp_size: 1g) are loaded into cfg.AgentOverrides and merged into the override parameter at sandbox.go:241-244 before Merge() is called. They hit the override.TmpSize > 0 branch and take precedence over global defaults. Only when no override exists does the else if apply the global default over the agent built-in.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions